Yuniframe: ANGLE+DX11でXboxに移植したい作戦
いやまぁANGLEは前にもXboxでは動かしてる https://twitter.com/okuoku/status/721780477644775430 んだけど
この当時は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 の順に移植していくことにする。
前回のパッチ類
前回はCMakeは完全手書きで、かつファイルもいくつか差し替えてビルドしている。
UWP対応のためのパッチはMSがGoogle側のリポジトリにupstreamしたのでもう不要。もっとも、今回の方針ではUWPのためのWindowまわりはSDL側にやらせるつもりなのでANGLE側のUWPサポート自体不要なはずだけど。。 → 実際には必要だった (hWndの代わりにCoreWindowを渡し、ANGLEにSwapChainを作らせている)
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には真の静的リンクをさせないようにする嫌がらせが導入されている。
- 静的リンクさせたくない背景を説明したドキュメント: https://github.com/libsdl-org/SDL/blob/4acd1dcad41d154093ca14eb0adf35f4f99bd06a/docs/README-dynapi.md
- 該当コード: https://github.com/libsdl-org/SDL/blob/4acd1dcad41d154093ca14eb0adf35f4f99bd06a/src/dynapi/SDL_dynapi.h#L25-L40
#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は提供していないため手書きは依然必要になる。
ANGLEはChromiumに依存している
このコミット以降Chromiumのzlibが無いとANGLEがビルドできないようだ。。さすがに1MiBくらいのライブラリのために毎回Chromiumをチェックアウトするのは厳しいものがあるので、コピーを持つことにした。
Yuniframe単体でDLLにするぶんには困らないけど、アプリケーションと静的リンクしようとした場合アプリケーション側のzlibと干渉しそうだな。。あんまり良いアイデアは無い。
ChromiumのzlibはSIMD最適化が一部入っている。
とりあえずWin32で絵出し
前回とは違って、SDLもANGLEも一切パッチなしで絵出しができた。
ANGLEのEGL拡張を使うと、WindowsのhWndとDirect3d deviceを基にGLES2コンテキストを作れるのでとりあえずそれを使って絵だし。
処理の流れは簡単で、
-
eglCreateDeviceANGLE
でID3D11Device
をEGLDeviceEXT
に変換する。 -
eglGetPlatformDisplayEXT
で取得したデバイスからEGLDisplay
を生成 - 以降は普通のEGL + OpenGL ESと同様に
eglCreateWindowSurface
でサーフェスを生成して描画
SDLはRender APIでDirectX11の初期化はできるものの、ANGLE側にSwapChainからサーフェスを生成する機能が無いっぽいので自前でDirectX11の初期化を実装してSDLはオーディオとかゲームパッド部分だけ使うことにする。(後で)
ただ、なんかflipが妙に遅い気がする。。VSYNC切って試した方が良いかな。。
WinRT でも動いた
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しないといけない。
- https://github.com/libsdl-org/SDL/blob/5ac6bd548376dc1547db673e9b41dd7cf5a1e777/CMakeLists.txt#L1496
if(WASAPI AND HAVE_AUDIOCLIENT_H AND HAVE_MMDEVICEAPI_H AND NOT WINDOWS_STORE)
NOT WINDOWS_STORE
は間違い。
→ した