Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lessons learned from porting Roloengine from iO...

Manish Mathai
November 28, 2013
62

Lessons learned from porting Roloengine from iOS to Android

Talk at DroidCon 2013 titled "Lessons learned from porting Roloengine from iOS to Android"

Manish Mathai

November 28, 2013
Tweet

Transcript

  1. roloengine iOS Internals • Written in Obj-C • OpenGL ES

    2.0 for rendering • OpenAL for audio • Custom Physics engine • Custom Animation engine • Custom asset format for models, animations
  2. Decision time Completely Native NDK provided “NativeActivity” Pros :- •

    Almost Ultimate control over memory management • Faster (?) Cons :- • No UI support • Many APIs not available via NDK Standard UI combined with C/C++ code invoked via JNI Pros :- • Easy access to java APIs • Leverage standard UI Cons :- • Adds GC overhead on UI • UI communication a hassle Hybrid approach vs
  3. roloengine iOS Android Internals • Written in Obj-C C++ (NDK)

    & Java (UI) • OpenGL ES 2.0 for rendering • OpenAL-soft for audio • Custom Physics engine • Custom Animation engine • Custom asset format for models, animations
  4. Rendering • Competent OpenGL ES 2.0 implementations from Android 2.3

    onwards. • DO NOT MIX OpenGL 1.0 & 2.0 calls. • Recreate glBegin() / glEnd(), glPushMatrix() / glPopMatrix semantics in 2.0 if needed.
  5. OpenGL context creation Pure Native a.k.a the hard way static

    int engine_init_display(struct engine* engine) { const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLint w, h, dummy, format; EGLint numConfigs; EGLConfig config; EGLSurface surface; EGLContext context; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  6. OpenGL context creation eglInitialize(display, 0, 0); eglChooseConfig(display, attribs, &config, 1,

    &numConfigs); eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); surface = eglCreateWindowSurface(display, config, engine->app->window, NULL); context = eglCreateContext(display, config, NULL, NULL); if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { LOGW("Unable to eglMakeCurrent"); return -1; } return 0; }
  7. OpenGL context creation Context creation in Java GLSurfaceView mGLView =

    new GLSurfaceView(this); mGLView.setRenderer(new GLRenderer()); class GLRenderer implements GLSurfaceView.Renderer { … public native void native_render(); public void onDrawFrame(GL10 gl) { native_render(); } }
  8. OpenGL context creation Rendering via JNI calls to C/C++ JNIEXPORT

    void JNICALL Java_com_example_package_native_render(JNIEnv *env_, jobject obj_) { // Drawing code goes here }
  9. OpenGL Tips • All OpenGL calls on render thread. All

    UI changes in UI thread. • Avoid touching Java heap during the game loop. • Block OpenGL thread on application pause.
  10. Audio • Java APIs (SoundPool & Media Player) vs Native

    API OpenSL ES • OpenSL ES has a horrible & convoluted API • OpenAL-soft - Software impl of OpenAL with OpenEL ES as the backend https://github.com/AerialX/openal-soft-android
  11. C++ utils & tools • Boost - surprisingly easy to

    build https://github.com/MysticTreeGames/Boost-for-Android Boost::Bind, Boost::IO • tinyxml2 - small and efficient XML parser https://github.com/leethomason/tinyxml2 • libpng + libzip for compressed textures
  12. UI • Android is stingy with memory (16-24MB) • Easy

    to hit OOM with large bitmaps. • Modern phones (1 GB+ RAM) too Solution :- BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true; options.inInputShareable = true;
  13. UI • Layouts for all screen sizes a must, for

    consistent UI placement. • Stock android fonts are limited.