Open5

em2native: Xbox(UWP)対応

okuokuokuoku

いやまぁUnityは普通にXbox版があるんでそっち使えよという話ではあるけど。。

(XboxのSDKには普通のゲームSDKとUWP -- Universal Windows Platform の2種類あるが今回は後者を扱う。前者はNDAが必要。)

いわゆるパッケージングが必要なプラットフォームに対応していく。Xbox(UWP) → iOS → Androidの順かな。一度やっておけば、.wasmでバイナリを出すだけで対応できるので色々と便利なはず。

制約

UWPはかなり制約がきつい。

  • VisualStudioしか使えない 。このため、一部をclangでビルドしたりするのは工夫が必要。
  • DLLをロードするための LoadLibrary が無い 。一応代替APIもあるがコード分けるのが面倒なのでアプリはclangでビルドした静的ライブラリにしたい。
  • ファイルをパッケージに格納する必要がある 。CMakeの場合、なんと add_executable にファイルリストを渡し、専用のプロパティ VS_DEPLOYMENT_CONTENT を設定する必要がある。
  • あとCMakeが生成する.slnが何か怪しかった気がする。

これらに対応するために、一旦プロジェクトを2つに分ける。

  1. Emscriptenアプリを 静的ライブラリ.lib とファイルリストの.cmakeに変換するプロジェクト(appプロジェクト)
  2. ↑のプロジェクトの生成物を取り込んでアプリケーションパッケージを生成するプロジェクト(runtimeプロジェクト)

前者のプロジェクトが wasm2c を実行し、後者のプロジェクトがYuniframeやDuktape等のランタイム部分をビルドすることになる。

okuokuokuoku

やっぱりビルドに時間が掛かる

とりあえず -ftime-report すると単なるコード生成だけで20分近く掛かっている。。つまりいわゆるプログラム全体を使った最適化パスは殆ど時間を消費していないので、.c出力を細かく分割してコード生成自体を並列化できるように配慮しない限りなんともならなさそう。

===-------------------------------------------------------------------------===
                      ... Pass execution timing report ...
===-------------------------------------------------------------------------===
  Total Execution Time: 4053.4531 seconds (4063.8098 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
  1150.8906 ( 29.7%)   0.2344 (  0.1%)  1151.1250 ( 28.4%)  1153.5091 ( 28.4%)  Simple Register Coalescing
  1119.5938 ( 28.9%)   6.3438 (  3.6%)  1125.9375 ( 27.8%)  1129.2749 ( 27.8%)  Machine Instruction Scheduler
  619.4688 ( 16.0%)  12.0938 (  6.9%)  631.5625 ( 15.6%)  634.0365 ( 15.6%)  X86 DAG->DAG Instruction Selection
  201.9531 (  5.2%)  127.2188 ( 72.5%)  329.1719 (  8.1%)  331.4470 (  8.2%)  X86 Assembly Printer
  194.8906 (  5.0%)   2.5625 (  1.5%)  197.4531 (  4.9%)  197.7001 (  4.9%)  Greedy Register Allocator
  77.9062 (  2.0%)   0.8281 (  0.5%)  78.7344 (  1.9%)  78.4326 (  1.9%)  SROA
  31.8125 (  0.8%)   0.4688 (  0.3%)  32.2812 (  0.8%)  32.3988 (  0.8%)  Interprocedural Sparse Conditional Constant Propagation
  25.6250 (  0.7%)   0.1562 (  0.1%)  25.7812 (  0.6%)  25.8445 (  0.6%)  Live DEBUG_VALUE analysis
  24.2188 (  0.6%)   0.0469 (  0.0%)  24.2656 (  0.6%)  23.9375 (  0.6%)  Combine redundant instructions
  23.7812 (  0.6%)   0.1094 (  0.1%)  23.8906 (  0.6%)  23.3037 (  0.6%)  Live Variable Analysis
  14.8438 (  0.4%)   0.0781 (  0.0%)  14.9219 (  0.4%)  15.1210 (  0.4%)  CodeGen Prepare
  13.9375 (  0.4%)   0.1406 (  0.1%)  14.0781 (  0.3%)  14.4494 (  0.4%)  Combine redundant instructions #3
  13.4531 (  0.3%)   0.3906 (  0.2%)  13.8438 (  0.3%)  13.8418 (  0.3%)  Called Value Propagation
  11.8281 (  0.3%)   0.1562 (  0.1%)  11.9844 (  0.3%)  12.3254 (  0.3%)  Combine redundant instructions #4
  12.3125 (  0.3%)   0.0938 (  0.1%)  12.4062 (  0.3%)  12.2225 (  0.3%)  Combine redundant instructions #2
  11.2656 (  0.3%)   0.2031 (  0.1%)  11.4688 (  0.3%)  11.9759 (  0.3%)  Combine redundant instructions #6
  10.8125 (  0.3%)   0.2500 (  0.1%)  11.0625 (  0.3%)  10.8868 (  0.3%)  Machine Copy Propagation Pass
   9.9375 (  0.3%)   0.0781 (  0.0%)  10.0156 (  0.2%)   9.6331 (  0.2%)  Combine redundant instructions #5
   9.2344 (  0.2%)   0.1406 (  0.1%)   9.3750 (  0.2%)   9.5385 (  0.2%)  Live Interval Analysis
   9.3906 (  0.2%)   0.0469 (  0.0%)   9.4375 (  0.2%)   9.0803 (  0.2%)  Combine redundant instructions #7
   8.7656 (  0.2%)   0.0312 (  0.0%)   8.7969 (  0.2%)   8.6794 (  0.2%)  Loop Strength Reduction
   8.3281 (  0.2%)   0.1094 (  0.1%)   8.4375 (  0.2%)   8.3696 (  0.2%)  Machine Common Subexpression Elimination
   8.3281 (  0.2%)   0.1094 (  0.1%)   8.4375 (  0.2%)   8.2371 (  0.2%)  Machine Copy Propagation Pass #2
okuokuokuoku

パッケージのファイルはRead-Writeでopenできない

Unityランタイムの起動中にopenに失敗してしまっているようだ。

procmonで見ると ACCESS DENIED で失敗しているが、これ C++ 的な意味の fstream はopenに失敗するだけで例外を投げないのでややこしい。。

https://github.com/okuoku/yuniframe/commit/2022228527c10691618c0e6f0ff6e513551ae2c5

@@ -37,6 +36,10 @@ file_open_gen(const char* path, yfrm_file_t** file,
             p = pth;
         }
         auto strm = new std::fstream(p, mode | std::ios_base::binary);
+        if(! strm->is_open()){
+            delete strm;
+            return -1;
+        }
         auto out = new yfrm_file_t();
         out->pth = new fs::path(p);
         out->strm = strm;

is_open でチェックして失敗するようにした。

okuokuokuoku

Xbox SeriesSでも動いた

PCで動いたものをそのままリモート起動するだけで動作した:

https://twitter.com/okuoku/status/1376059283305943046

やっぱりUniversalだ!

スタートアップ画像の張り込みとか他のパッケージング作業は後で実装するというかiOSとAndroidとでその辺の仕様がバラバラなのでインターフェースを考えるのが大変。。

サインインしていないと実行できない

(任天堂やSonyのゲーム機と異なり、ChromeOS機のように、)Xboxは本来MSアカウントにサインインしていないと機能しないコンソールなので、1アカウントもデバイスにサインインしていない状態ではアプリケーションが起動しない。

Visual Studioから起動するとちょっとわかりづらいダイアログが出るだけだが、

Windows ストア アプリ 'DB799910-475A-3CAF-98E6-7E47316BAA7C_d7c8pgvss6ysm!App' をアクティブにできません。アクティベーション要求がエラー '操作はサポートされていません。不明なエラー: 0x8004090a' で失敗しました。

実機で直接起動するとちゃんとメッセージが出る: