package com.eaglesakura.view.egl; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL11; import android.graphics.SurfaceTexture; import android.os.Looper; import com.eaglesakura.view.GLTextureView.EGLConfigChooser; import com.eaglesakura.view.GLTextureView.GLESVersion; public class EGLManager { /** * ロックオブジェクト */ final private Object lock = new Object(); /** * EGLオブジェクト */ EGL10 egl = null; /** * レンダリング用ディスプレイ */ EGLDisplay eglDisplay = null; /** * レンダリング用サーフェイス */ EGLSurface eglSurface = null; /** * レンダリング用コンテキスト */ EGLContext eglContext = null; /** * config情報 */ EGLConfig eglConfig = null; /** * システムがデフォルトで使用しているEGLDisplayオブジェクト */ EGLDisplay systemDisplay = null; /** * システムがデフォルトで使用しているEGLSurface(Read) */ EGLSurface systemReadSurface = null; /** * システムがデフォルトで使用しているEGLSurface(Draw) */ EGLSurface systemDrawSurface = null; /** * システムがデフォルトで使用しているコンテキスト */ EGLContext systemContext = null; /** * GL10 object * only OpenGL ES 1.1 */ GL11 gl11 = null; public EGLManager() { } /** * 初期化を行う */ public void initialize(final EGLConfigChooser chooser, final GLESVersion version) { synchronized (lock) { if (egl != null) { throw new RuntimeException("initialized"); } egl = (EGL10) EGLContext.getEGL(); // システムのデフォルトオブジェクトを取り出す { systemDisplay = egl.eglGetCurrentDisplay(); systemReadSurface = egl.eglGetCurrentSurface(EGL10.EGL_READ); systemDrawSurface = egl.eglGetCurrentSurface(EGL10.EGL_DRAW); systemContext = egl.eglGetCurrentContext(); } // ディスプレイ作成 { eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); if (eglDisplay == EGL10.EGL_NO_DISPLAY) { throw new RuntimeException("EGL_NO_DISPLAY"); } if (!egl.eglInitialize(eglDisplay, new int[2])) { throw new RuntimeException("eglInitialize"); } } // コンフィグ取得 { eglConfig = chooser.chooseConfig(egl, eglDisplay, version); if (eglConfig == null) { throw new RuntimeException("chooseConfig"); } } // コンテキスト作成 { eglContext = egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, version.getContextAttributes()); if (eglContext == EGL10.EGL_NO_CONTEXT) { throw new RuntimeException("eglCreateContext"); } } if (version == GLESVersion.OpenGLES11) { gl11 = (GL11) eglContext.getGL(); } } } /** * get GL11 object * @return */ public GL11 getGL11() { if (gl11 == null) { throw new UnsupportedOperationException("OpenGL ES 1.1 only"); } return gl11; } public EGLConfig getConfig() { return eglConfig; } public EGLSurface getSurface() { return eglSurface; } public EGLContext getContext() { return eglContext; } /** * リサイズを行う * @param view */ public void resize(SurfaceTexture surface) { synchronized (lock) { // 既にサーフェイスが存在する場合は廃棄する if (eglSurface != null) { egl.eglDestroySurface(eglDisplay, eglSurface); } // レンダリング用サーフェイスを再度生成 { eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surface, null); if (eglSurface == EGL10.EGL_NO_SURFACE) { throw new RuntimeException("eglCreateWindowSurface"); } } } } /** * 解放処理を行う */ public void destroy() { synchronized (lock) { if (egl == null) { return; } if (eglSurface != null) { egl.eglDestroySurface(eglDisplay, eglSurface); eglSurface = null; } if (eglContext != null) { egl.eglDestroyContext(eglDisplay, eglContext); eglContext = null; } eglConfig = null; egl = null; } } /** * ES20コンテキストを専有する */ public void bind() { synchronized (lock) { egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); } } /** * UIスレッドで呼び出された場合trueを返す。 * @return */ public boolean isUIThread() { return Thread.currentThread().equals(Looper.getMainLooper().getThread()); } /** * コンテキストの専有を解除する */ public void unbind() { synchronized (lock) { if (isUIThread()) { // UIスレッドならばシステムのデフォルトへ返す egl.eglMakeCurrent(systemDisplay, systemDrawSurface, systemReadSurface, systemContext); } else { // それ以外ならば、null状態に戻す egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); } } } /** * 最後のリリースタイミングではNO_SURFACEで問題ない。 */ public void releaseThread() { synchronized (lock) { egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); } } /** * レンダリング内容をフロントバッファへ転送する */ public boolean swapBuffers() { synchronized (lock) { return egl.eglSwapBuffers(eglDisplay, eglSurface); } } }