Open5

Yuniframe: ANGLE+DX11でXboxに移植したい作戦

okuokuokuoku

いやまぁANGLEは前にもXboxでは動かしてる https://twitter.com/okuoku/status/721780477644775430 んだけど

https://www.youtube.com/watch?v=OqdW7qjPlHg

この当時はSDLとANGLEの双方にパッチを当ててて割と無理矢理感のある実装だった。

作戦

C-WebGLはそのうちDirectXで直接動かしたいとは思っているけどあまり優先度は高くない。

  • 可能な限りupstreamをそのまま使う (前回はパッチ上等だった)
  • ANGLEとSDLは静的リンクする
  • SDL側のEGL層は使わない (前回はSDLのEGL層にパッチして静的リンクに対応した)
  • SDLのRenderとしてDirectX11を初期化させ、 それをANGLEに渡して OpenGL ES2の描画をする → SwapChainをSDLと共有するのは無理だったので諦めた

Win32 App → PC UWP → Xbox UWP の順に移植していくことにする。

okuokuokuoku

前回のパッチ類

https://github.com/okuoku/sdl2-static-cmake

https://github.com/okuoku/angle-static-cmake

前回はCMakeは完全手書きで、かつファイルもいくつか差し替えてビルドしている。

UWP対応のためのパッチはMSがGoogle側のリポジトリにupstreamしたのでもう不要。もっとも、今回の方針ではUWPのためのWindowまわりはSDL側にやらせるつもりなのでANGLE側のUWPサポート自体不要なはずだけど。。 → 実際には必要だった (hWndの代わりにCoreWindowを渡し、ANGLEにSwapChainを作らせている)

https://github.com/google/angle/commit/11dc16350cd4d1990c6bcce43c73aff178a01086

Note that this doesn't bring back support for Windows/Phone 8.1.

超さみしい。

SDLのCMakeビルドサポートは割と改善したので、手書きしたCMakeListsは今回は捨てられそう。ただしSDLに付属のCMakeLists.txtは GLOB に依存しているため、安全なビルドのためには毎回 cmake を走らせる必要はある。公式には GLOB でソースコードを列挙するのは推奨されていないが、割と大企業もこのルールを守っていない。

We do not recommend using GLOB to collect a list of source files from your source tree.

SDLには真の静的リンクをさせないようにする嫌がらせが導入されている。

#ifdef SDL_DYNAMIC_API  /* Tried to force it on the command line? */
#error Nope, you have to edit this file to force this off.
#endif

もっとも、これは嫌がらせとして機能していない。このヘッダはシンボル SDL_DYNAMIC_API しか定義しないため、単に -DSDL_dynapi_h_ -DSDL_DYNAMIC_API=0 すれば(ヘッダファイル全体をスキップさせることで)回避できてしまう。

ANGLEは当然CMakeLists.txtは提供していないため手書きは依然必要になる。

okuokuokuoku

ANGLEはChromiumに依存している

https://github.com/google/angle/commit/b55f0f78420f3c96f91b6de83f114a60967afa0c

このコミット以降Chromiumのzlibが無いとANGLEがビルドできないようだ。。さすがに1MiBくらいのライブラリのために毎回Chromiumをチェックアウトするのは厳しいものがあるので、コピーを持つことにした。

https://github.com/okuoku/angle-static-cmake/commit/6d331ae4be986e049362f1c6bafbff5a12b49ccc

Yuniframe単体でDLLにするぶんには困らないけど、アプリケーションと静的リンクしようとした場合アプリケーション側のzlibと干渉しそうだな。。あんまり良いアイデアは無い。

ChromiumのzlibはSIMD最適化が一部入っている。

okuokuokuoku

とりあえずWin32で絵出し

前回とは違って、SDLもANGLEも一切パッチなしで絵出しができた。

https://github.com/okuoku/yuniframe/commit/b4e46909a2173b5ee83853dc1ee6c82b4d746397

ANGLEのEGL拡張を使うと、WindowsのhWndとDirect3d deviceを基にGLES2コンテキストを作れるのでとりあえずそれを使って絵だし。

処理の流れは簡単で、

  1. eglCreateDeviceANGLEID3D11DeviceEGLDeviceEXT に変換する。
  2. eglGetPlatformDisplayEXT で取得したデバイスから EGLDisplay を生成
  3. 以降は普通のEGL + OpenGL ESと同様に eglCreateWindowSurface でサーフェスを生成して描画

SDLはRender APIでDirectX11の初期化はできるものの、ANGLE側にSwapChainからサーフェスを生成する機能が無いっぽいので自前でDirectX11の初期化を実装してSDLはオーディオとかゲームパッド部分だけ使うことにする。(後で)

ただ、なんかflipが妙に遅い気がする。。VSYNC切って試した方が良いかな。。

okuokuokuoku

WinRT でも動いた

https://github.com/okuoku/yuniframe/commit/a1fb7454dfcc5c52d1f220102f96ca430c548b3a

SDLにDX11を初期化させるのを止めて手動で初期化するようにした。 ...こういうのをやりたくないからSDL使ってるんだけどなぁ。。

ToDo

ちょっと動作確認している暇が無いけどSDLにupstreamしないといけない項目2点。

エラー LNK1169 1 つ以上の複数回定義されているシンボルが見つかりました。 fwtest C:\build\yfrmuwp\Debug\fwtest.exe 1
エラー LNK2005 IID_IDXGIFactory2 は既に SDL2d.lib(SDL_winrtvideo.obj) で定義されています。 fwtest C:\build\yfrmuwp\dxguid.lib(d3d10guid.obj) 1

IID_IDXGIFactory2 はSDKシンボルなのにSDLのソースコード内で自前で定義してしまっている。これは衝突するのでrenameしないといけない。

if(WASAPI AND HAVE_AUDIOCLIENT_H AND HAVE_MMDEVICEAPI_H AND NOT WINDOWS_STORE)

NOT WINDOWS_STORE は間違い。

→ した

https://github.com/libsdl-org/SDL/pull/4273

https://github.com/libsdl-org/SDL/pull/4275