- Use Android SurfaceView for rendering surface.
- In native code, create a rendering thread and call OpenGL for rendering in the same thread.
1. Workflow
2. Demo
Source code can be found on my github page: https://github.com/chuzcjoe/nativegl
On Android side, we start/stop rendering at different stages of the SurfaceView lifecycle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class SurfaceViewHolder : SurfaceHolder.Callback { override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { JNIProxy.setSurface(holder.surface) JNIProxy.startRender() }
override fun surfaceCreated(holder: SurfaceHolder) { JNIProxy.calPixel() JNIProxy.setSurface(holder.surface) JNIProxy.startRender() }
override fun surfaceDestroyed(holder: SurfaceHolder) { JNIProxy.stopRender() JNIProxy.setSurface(null) } }
|
To start rendering, we will start a new rendering thread. In this new thread, we will initialize EGL settings and start drawing with OpenGL APIs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| void GLBase::StartRenderThread(){ if (!init){ _th = std::thread(RenderThread, this); init = !init; } running = true; }
void GLBase::RenderThread(GLBase* obj){ obj->RenderLoop(); }
void GLBase::RenderLoop(){ bool rendering = true; while (rendering) { if (running){ if (eglSetting._msg == EGLSetting::RenderThreadMessage::MSG_WINDOW_SET) { initEGL(); } if (eglSetting._msg == EGLSetting::RenderThreadMessage::MSG_RENDER_LOOP_EXIT) { rendering = false; DestroyRender(); } eglSetting._msg = EGLSetting::RenderThreadMessage::MSG_NONE;
if (!window_set) { usleep(16000); continue; }
if (eglSetting._display) { std::lock_guard<std::mutex> lock(eglSetting._mutex); DrawFrame(); if (!eglSwapBuffers(eglSetting._display, eglSetting._surface)) { LOG_INFO("GLrenderS::eglSwapBuffers() returned error %d", eglGetError()); } } else { usleep(16000); } } else { usleep(16000); } } }
|
If everything works well, you should see a green triangle at the center of the screen.