Sunday, December 1, 2013

Porting to Windows Phone 8

Adapting VLAD to WP8 has been harder and more expensive than other mobile platforms. Still, I'm glad I took the bullet, because I ended up with a much more mature game engine, and I have a foot (or two) in the Windows Store.

The Technical Challenges
Where do I begin.. Well, it started in a good place: I'm used to writing cross-platform code and I always liked porting code to new platforms. I find it beautiful to see a game running consistently across completely different systems. It's an important testament to solid engineering, and as an engine programmer, this is where I get most of my satisfaction!

In the case of WP8, porting was probably as challenging as it gets, and this is starting with an already cross-platform engine that runs on PC/iOS/Android.

Graphics: This was by far the most challenging part, I should probably dedicate a blog post to give you more details about it. But in short, coming from OpenGL, writing a DX11 renderer is no cake walk. I don't even remember the year when I last used DirectX, I just know it was DirectX 9 at the time and I was doing simple fixed-pipeline stuff with it. DirectX11 is a whole new world, even more so that it's mandatory to use shaders to get anything on the screen. This will be definitely addressed in a separate post with more details.

It's worth noting that I spent a fair amount of time dealing with the notorious DX COM interface leaks (they show up when using the debug DX runtime). I used to ignore them in the old DX9 days, but this time I wanted to make my engine completely leak free. So I wrote a templated wrapper around DX interfaces, mimicking the COMRef<> C# wrapper, but in C++. Also, I didn't find any quick way of supporting Point Sprites (which I was using everywhere in the GL port) so I had to let go of them and use bill-boarded particles across the board. But generally speaking, DX11 feels future-proof and powerful to use, and that you can rely on it when developing more advanced features. The price being that it's relatively more complex to get something simple rolling specially compared to GL. As an example, here are the DX interfaces needed just to get my GraphicDriver rolling (this is not including textures, vertex buffers, shaders, or other graphic objects):


COMReference<IDXGISwapChain1> m_SwapChain;  
COMReference<ID3D11RenderTargetView> m_RenderTargetView;  
COMReference<ID3D11DepthStencilView> m_DepthStencilView;  
COMReference<ID3D11Buffer> m_MVPBuffer;  
COMReference<ID3D11Buffer> m_TextureTransformBuffer;  
COMReference<ID3D11Buffer> m_MaterialBuffer;  
COMReference<ID3D11SamplerState> m_TextureSamplerLinear;  
COMReference<ID3D11BlendState> m_BlendState[2][D3D11_BLEND_INV_SRC1_ALPHA+1][D3D11_BLEND_INV_SRC1_ALPHA+1]; // blendEnable / srcBlend / destBlend  
COMReference<ID3D11DepthStencilState> m_DepthStencilState[2][2][D3D11_COMPARISON_ALWAYS+1]; // testEnable / writeEnable / depthFunc  
COMReference<ID3D11RasterizerState> m_RasterizerState[2][D3D11_FILL_SOLID+1][D3D11_CULL_BACK+1]; // frontCCW / fillMode / cullMode  
COMReference<ID3D11DeviceContext1> m_ImmediateContext;  
COMReference<ID3D11Device1> m_Device;  
   

File system: For this part, the challenge was to find good information on where to start. Just google "WP8 open file from C++" and get a load of the range of approaches available out there. So I followed multiple leads, before settling for the good old LibC! Yes, fopen works like a charm on WP8, provided you access your files relative to the correct system paths. Here is how I determine the application folder and the writable (for savegame) folder on WP8:


Platform::String^ dataPath = Windows::ApplicationModel::Package::Current->InstalledLocation->Path;  
std::wstring dataPathW(dataPath->Begin());  
std::string dataPathMB(dataPathW.begin(), dataPathW.end());  
shoot::File::SetBasePath(dataPathMB.c_str());  
        
Platform::String^ writablePath = Windows::Storage::ApplicationData::Current->LocalFolder->Path;  
std::wstring writablePathW(writablePath->Begin());  
std::string writablePathMB(writablePathW.begin(), writablePathW.end());  
shoot::File::SetWritablePath(writablePathMB.c_str());  
   

Multi-threading: Same challenge as for the file system, the hard part was finding a simple approach that works well! For this one, C++11 saves the day. Long story short, std::mutex and std::thread work great on WP8, while being incredibly simple to use.

Networking: This was a special case and deserves an article on its own, because I wrote the networking part for all platforms at once, there was no real porting involved. But the bottom line is that I use the good old Winsock2 for network communication on WP8.

The Development Costs
The highest compared to iOS and Android: You basically need a Windows 8 Pro computer. In my case this implied buying a new computer, and buying a Windows 8 Pro license. Also, because I was serious about my game, I had to buy an HTC phone for testing.



No comments:

Post a Comment