Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

cocos2dx 3.17でASTCフォーマット使ってみた

こんにちは! Suです。
この記事は Akatsuki Advent Calendar 2022 24日目の記事です。
昨日はいたみんさんの Jenkins Log Parser Plugin の話でした。
色つけてログがみやすくなります。うちのプロジェクトにも導入したいですね〜
読みやすくていい記事でした。勉強になりました!

はじめに

cocos2d-x-3.17.2 はASTCという画像フォーマットをサポートしないので、サポートできるように色々頑張ったことをここに書き残します。
ソフトウェアデコードとハードウェアデコード両方とも実装してみました。

ASTC とは?

ASTCは綺麗で容量もそこそこ抑えられるテクスチャの圧縮フォーマットです。
iPhone6 以降、2015年以降に発売したAndroid端末などは大体使えます。

Block サイズは大きくなるど、綺麗に見えるがサイズも増えます。
ASTC のアルゴリズムはこの文章にて詳しく紹介しません 🙏 

cocos2dx は ASTC サポートしていますが、Axoml という cocos2dx-4.0 から派生したゲームエンジンはサポートしています。それを参考しつづ cocos2dx-3.17 で実装してみます!

ASTCソフトウェアデコード

まず Axoml エンジンから ASTC デコードコードを拝借いたします。

ASTCデコードライブラリ置く場所
ファイル/フォルダ 場所
axmol/astc.h cocos2d/cocos/base
axmol/astc.cpp cocos2d/cocos/base
axmol/thirdparty/astc cocos2d/external

xcodeprojに追加することもお忘れ無く!

 

ここでビルドして問題ないと確認しましょう。

続いて端末が ASTC に対応できるのかの実装です。
他のフォーマットを真似して、CCImage に ASTC の実装を追加します。

bool Image::isASTC(const unsigned char *data, ssize_t dataLen)
bool Image::initWithASTCData(const unsigned char * data, ssize_t dataLen)

を新規追加して、既存の

Image::initWithImageData(const unsigned char * data, ssize_t dataLen)
Image::detectFormat(const unsigned char * data, ssize_t dataLen)

に ASTC の分岐文を追加します。

▼クリックでコードを表示する

 

最後に HellowWorldScene に astc 画像を表示するボタンを作成します。
画像はみなさんご存知のレナさんにしました。
下記の ARM 社の astc-encoder を使って PNG から ASTC に変換しました。

▼クリックでコードを表示する


下記はソフトウェアデコードがかかった時間です。
ASTC 8x8のサイズ圧倒的に優秀ですが、
やはり遅いですね...ハードウェアでコード実装しないと使えないの気がします。

ASTCソフトウェアデコード
解像度 フォーマット サイズ 時間
512 png 386KB 約35ms
512 astc 4x4 226KB 約270ms
512 astc 8x8 70KB 約300ms
1024 png 1.4MB 約80ms
1024 astc 4x4 1.1MB 約892ms
1024 astc 8x8 266KB 約930ms
1960 png 4.1MB 約185ms
1960 astc 4x4 3.8MB 約3100ms
1960 astc 8x8 963KB 約3210ms

※時間は10回平均、cacheなし

動画はこちらです

ASTCハードウェアデコード

まず最初の問題は、GLES 3.0 から ASTC ldr が対応していますが、cocos2dx-3.17 が GLES 3 に対応しないです。昔一時 GLES 3.0 対応させたですが、どうやら一部 Android シミュレーターがクラッシュするとパフォーマンスの問題で revert されたみたいです。

実験として、ios を GLES 3.0 に対応させます。

▼クリックでコードを表示する

 

手元の端末 iPhone 8 で対応できる ASTC フォーマットを調べると、ldr しか対応できないので、今回はそれを対応させてみます。

GL_KHR_texture_compression_astc_ldr 

ちなみに、このサイトで対応しない端末が調べます。

端末が ASTC に対応できるのかをチェックするため、CCConfiguration に isSupportsASTC() を追加します。

▼クリックでコードを表示する

 

続いて ASTC 4x4、8x8 のPixelFormat を追加します。
それそれの internalformat は この仕様書 に書かれてます。

COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7

▼クリックでコードを表示する

 

bpp(BitsPrePixel) は Wikipedia で確認できます。

Block footprint Bit rate
4×4 8.00
8×8 2.00

主に下記 CCTexture2D.cpp の PixelFormat マップに ASTC の項目を追加することです。

static const PixelFormatInfoMapValue TexturePixelFormatInfoTablesValue[]

▼クリックでコードを表示する

 

最後にCCImage.cppにハードウェアデコードの処理を追加すればOK!

▼クリックでコードを表示する

 

では時間を測ってみましょう〜

ASTCデコード
解像度 フォーマット サイズ ソフトウェア時間 ハードウェア時間
512 png 386KB 約35ms 約35ms
512 astc 4x4 226KB 約270ms 約3ms
512 astc 8x8 70KB 約300ms 約2ms
1024 png 1.4MB 約80ms 約80ms
1024 astc 4x4 1.1MB 約892ms 約5ms
1024 astc 8x8 266KB 約930ms 約3ms
1960 png 4.1MB 約185ms 約185ms
1960 astc 4x4 3.8MB 約3100ms 約17ms
1960 astc 8x8 963KB 約3210ms 約6ms

※時間は10回平均、cacheなし

爆速じゃん!!!
Fooooooo 🎉🎉🎉

動画はこちらです

Github repo もありますー


最後に

ハードウェアデコードがすごかった...
Androidも試したいですね 🤔
もし今後他のフォーマットを追加したい時、もっとちゃんとしたコード書かないと思いますが、大体同じやり方でできると思います。
自分のメモもなりましたし、この記事読んだ君の役に立てればいいですね〜

明日は Sieben.L さんのドライブと関連した内容です。楽しみですね!

アカツキでは一緒に働くエンジニアを募集しています。
カジュアル面談もやっていますので、気軽にご応募ください。
https://hrmos.co/pages/aktsk/jobs?category=1220948640529788928