package com.glview.hwui; import static javax.microedition.khronos.egl.EGL10.EGL_BAD_NATIVE_WINDOW; import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY; import static javax.microedition.khronos.egl.EGL10.EGL_DRAW; import static javax.microedition.khronos.egl.EGL10.EGL_NONE; import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT; import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY; import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE; import static javax.microedition.khronos.egl.EGL10.EGL_SUCCESS; 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.GL; import android.opengl.EGL14; import android.opengl.GLUtils; import android.util.Log; /** * Learn from Android5.0 hwui library. * @author lijing.lj */ class EglManager { final static String TAG = "EglManager"; final static boolean DEBUG = true; int mEGLContextClientVersion = 2; static EGL10 sEgl; static EGLDisplay sEglDisplay; static EGLConfig sEglConfig; EGLContext mEglContext; EglManager() { initializeEgl(); } void initializeEgl() { if (hasEglContext()) return; if (sEgl == null && sEglConfig == null) { sEgl = (EGL10) EGLContext.getEGL(); // Get to the default display. sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY); if (sEglDisplay == EGL_NO_DISPLAY) { throw new RuntimeException("eglGetDisplay failed " + GLUtils.getEGLErrorString(sEgl.eglGetError())); } // We can now initialize EGL for that display int[] version = new int[2]; if (!sEgl.eglInitialize(sEglDisplay, version)) { throw new RuntimeException("eglInitialize failed " + GLUtils.getEGLErrorString(sEgl.eglGetError())); } checkEglErrorsForced(); sEglConfig = loadEglConfig(); } if (mEglContext == null) { // Create the EGLContext mEglContext = createContext(sEgl, sEglDisplay, sEglConfig); } } boolean hasEglContext() { return mEglContext != null; } private boolean checkEglErrorsForced() { int error = sEgl.eglGetError(); if (error != EGL_SUCCESS) { // Something bad has happened Log.w(TAG, "EGL error: " + GLUtils.getEGLErrorString(error)); destroy(); return false; } return true; } private EGLConfig loadEglConfig() { return new GLViewEGLConfigChooser(8, 8, 8, 8, 8, 0, 0, mEGLContextClientVersion).chooseConfig(sEgl, sEglDisplay); // int[] attribs; // attribs = new int[] { // EGL10.EGL_RED_SIZE, 8, // EGL10.EGL_GREEN_SIZE, 8, // EGL10.EGL_BLUE_SIZE, 8, // EGL10.EGL_ALPHA_SIZE, 8, // EGL10.EGL_DEPTH_SIZE, 0, // EGL10.EGL_CONFIG_CAVEAT, EGL_NONE, // EGL10.EGL_STENCIL_SIZE, 0, // EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, // EGL10.EGL_NONE // }; // // attribs = filterConfigSpec(attribs); // int num_configs[] = new int[]{1}; // EGLConfig[] configs = new EGLConfig[num_configs.length]; // if (!sEgl.eglChooseConfig(sEglDisplay, attribs, configs, num_configs.length, num_configs) || num_configs[0] != 1) { // throw new RuntimeException("eglConfig choose failed"); // } // EGLConfig eglConfig = configs[0]; // if (eglConfig == null) { // throw new RuntimeException("eglConfig not initialized"); // } // return eglConfig; } // private int[] filterConfigSpec(int[] configSpec) { // if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) { // return configSpec; // } // /* We know none of the subclasses define EGL_RENDERABLE_TYPE. // * And we know the configSpec is well formed. // */ // int len = configSpec.length; // int[] newConfigSpec = new int[len + 2]; // System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); // newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; // if (mEGLContextClientVersion == 2) { // newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */ // } else { // newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */ // } // newConfigSpec[len+1] = EGL10.EGL_NONE; // return newConfigSpec; // } EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion, EGL_NONE }; EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, mEGLContextClientVersion != 0 ? attribs : null); if (context == null || context == EGL_NO_CONTEXT) { //noinspection ConstantConditions throw new IllegalStateException( "Could not create an EGL context. eglCreateContext failed with error: " + GLUtils.getEGLErrorString(sEgl.eglGetError())); } return context; } EGLSurface createSurface(Object surface) { initializeEgl(); EGLSurface eglSurface = null; try { eglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null); } catch (IllegalArgumentException e) { // This exception indicates that the surface flinger surface // is not valid. This can happen if the surface flinger surface has // been torn down, but the application has not yet been // notified via SurfaceHolder.Callback.surfaceDestroyed. // In theory the application should be notified first, // but in practice sometimes it is not. See b/4588890 Log.e(TAG, "eglCreateWindowSurface", e); } if (eglSurface == null || eglSurface == EGL_NO_SURFACE) { int error = sEgl.eglGetError(); Log.e(TAG, "createWindowSurface failed " + GLUtils.getEGLErrorString(error)); if (error == EGL_BAD_NATIVE_WINDOW) { Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); } return null; } if (!makeCurrent(eglSurface)) { Log.e(TAG, "eglMakeCurrent failed " + GLUtils.getEGLErrorString(sEgl.eglGetError())); } return eglSurface; } boolean makeCurrent(EGLSurface surface) { if (surface == null || surface == EGL10.EGL_NO_SURFACE) { return false; } if (!surface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) && !sEgl.eglMakeCurrent(sEglDisplay, surface, surface, mEglContext)) { return false; } return true; } void destroySurface(EGLSurface surface) { if (surface != null && surface != EGL_NO_SURFACE) { if (surface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) { sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } sEgl.eglDestroySurface(sEglDisplay, surface); } } GL getGL() { initializeEgl(); return mEglContext.getGL(); } void destroy() { if (mEglContext != null) { sEgl.eglDestroyContext(sEglDisplay, mEglContext); mEglContext = null; } } boolean swapBuffers(EGLSurface surface) { sEgl.eglSwapBuffers(sEglDisplay, surface); int error = sEgl.eglGetError(); if (error == EGL10.EGL_SUCCESS) { return true; } Log.w(TAG, "EGL error: " + GLUtils.getEGLErrorString(error)); if (error == EGL10.EGL_BAD_SURFACE) { // Tell them to recreate the surface. return false; } // Shouldn't reach here. Maybe we lost our egl context? // Check this error and fix it. throw new RuntimeException(String.format("Encountered EGL error %d %s during rendering", error, GLUtils.getEGLErrorString(error))); // destroy(); // return false; } }