Tips on porting to Apple platforms

Started by
4 comments, last by ddyer 6 years, 1 month ago

Hey folks,

I have been thinking about porting my tech stack (engine + game prototype) to Apple products for some time now. I have done some Mac development in the past, small scale Cocoa desktop development 10 years ago or so. I realize I have fallen out of the Apple development loop completely and don't really know what's what anymore. So I ask you for pointers and tips on how to proceed.

Some background:

- My game is a classical Win32 app linking to my main engine library, which is a DLL. The engine can then load any number of plugin DLLs at runtime. Eg. the rendering backends are loaded as plugins. If you know how OGRE loads render systems you get the idea, as that was what inspired me back in the day.

- The current version of the engine has rendering backends for DX11, DX12 and Vulkan, and the abstraction layer is written with the modern APIs in mind, ie. it exposes command queues, command buffers, PSOs, fences etc. Because of this I imagine I should target Metal rather than try to bolt an OpenGL backend onto it for the Apple platforms.

My first order of business would be to get a simple test app (eg. a spinning cube) running on an iPad Air 2. I have a few questions on how to get started:

1. What kind of projects do I want to set up in XCode? What should the actual game be? Xcode offers me something called a "Game". Is that the right one? Or perhaps "Single view app"? Keep in mind that the game would probably not be the thing that instantiates the window. In my windows builds the game contains mostly game-specific code. The engine library contains the code for loading a renderer backend DLL which then sets up the actual window (plain Win32 window for D3D-backends and a GLFW window for Vulkan). Can I do the same on iOS? Or does the game itself have to create the window on iOS?

2. What about the engine library and the plugin libraries? What kinds of projects do I create for them? XCode offers something called a Cocoa Touch Library, but that sounds like it is related to the touch UI somehow.

3. On windows the game runs in a typical main loop, something like:


void main()
{
    startup();

    while(running)
    {
        update();
        render();
    }

    shutdown();
}

Can I use the same kind of structure on iOS with a Metal backend? Most Metal tutorials I see use some kind of view that has a draw callback that it fires when it is time to draw things. That's fine as well if that is how the OS wants me to structure the game, but that would require some changes to how the game is set up. If that's the case, where do I put all of the non-rendering code, ie. the world update etc. Is there a separate place for that or do I put all of the update in the draw callback?

4. Should I be using something like SDL for this? I did some googling and it seems people have made Metal work with SDL but it is all highly WIP or unofficial. SDL seems to offer the plain old update/render loop structure I mentioned above, even on iOS, but does that work well with Metal? Or is it better to let the OS call into your code for updating/rendering?

Thanks!

Advertisement

Really? No-one knows? This seems like a fairly typical scenario to me, iOS being as popular as it is.

Anyway, I took the sword as it is dangerous to go alone, and started porting my core library. For now I am going with a Cocoa Touch Shared Library, as it seems to be the closest to what I have on Windows. Apparently iOS supports loading shared libraries since iOS 8 so I should be good regarding that. It seems like this produces a "framework" which is a bundle containing the dylib file + headers and resources, which is cool I guess. Still not sure if I actually need that or not.

For the plugins I am thinking about having straight dylib files but I am still unsure if I need resources to create a .nib file or whatever the windowing resources are called nowadays, in which case a framework would be better.

Seems like I should be able to drive the update/render logic the way I normally do but it remains to be seen if that is a good idea or not. Seems like the CADisplayLink is the preferred way to render, so I might want to add support for that later.

It will be a while before I have even the core lib compiling on clang, so I don't have to worry about that right now.

Thoughts?

You have to be a little careful about the platform's event loop on all of Apple's platforms. In particular, if you want to run the main loop from your code, you need to make sure to pump the native event loop regularly (if you wait too long, your app may be marked as non-responsive, i.e. the spinning beachball on Mac).

You also need to create/destroy an NSAutoreleasePool each time you pump the event loop. Otherwise you'll leak native memory very quickly :)

I tend to structure the code so that my main loop is a callback - on windows main() can just invoke the callback in a loop, on iOS the native event loop can invoke it repeatedly (plus, if you plan to cross-compile for the web via Emscripten, this is mandatory).

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Don't know how I missed your response, only saw your message now. Anyway, thanks!

Yes, it seems like the safest way to go with Apple platforms (and probably most power-aware platforms, ie. mobile) is to have the OS update the app rather than doing it yourself. Luckily I planned for this some years ago when setting up my engine base and the engine lets the application take care of the main loop however it wants as long as it calls certain things in a certain order during one update.

I found this (http://floooh.github.io/2016/01/15/oryol-metal-tour.html) article which suggests doing the same, ie. hook the update into the draw callback of MTKView, which is probably what I am going to do.

However, after spending years developing only on MSVC it will take some time still before I can even build the core engine library on clang, so it will be some time before I get to implement this. But it's all good, the codebase becomes more mature through all this. I have also found some subtle bugs and some questionable code that MSVC has (erronously) swallowed without a warning.

Your engine code will work unchanged, but everything related to graphics, events, and interaction with system services is different in many ways.   The cleanest way to approach the problem is to rewrite using some existing cross-platform environment that supports your desired set of platforms.   Trying to learn "just enough" of native apple to get by and do your own adaption will make you crazy.

 

---visit my game site http://www.boardspace.net - free online strategy games

This topic is closed to new replies.

Advertisement