From f8abdbf91a9996a008a11c47e4a92334a323fc12 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 19 Jan 2014 18:29:43 -0500 Subject: [PATCH] [Android] Initial introduction of the EGLHelper utility class. Should simplify all interop with the EGL/GL APIs. Not hooked up yet. However it is entirely functional. --- .../dolphinemu/utils/EGLHelper.java | 295 ++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java new file mode 100644 index 0000000000..2633ad681b --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java @@ -0,0 +1,295 @@ +package org.dolphinemu.dolphinemu.utils; + +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.GL10; + +import android.util.Log; + +/** + * Utility class that abstracts all the stuff about + * EGL initialization out of the way if all that is + * wanted is to query the underlying GL API for information. + */ +public final class EGLHelper +{ + private final EGL10 mEGL; + private final EGLDisplay mDisplay; + private EGLConfig[] mEGLConfigs; + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private GL10 mGL; + + // GL support flags + private boolean supportGL; + private boolean supportGLES2; + private boolean supportGLES3; + + // Renderable type bitmasks + public static final int EGL_OPENGL_ES_BIT = 0x0001; + public static final int EGL_OPENGL_ES2_BIT = 0x0004; + public static final int EGL_OPENGL_BIT = 0x0008; + public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; + + /** + * Constructor + * + * @param width Width of the underlying {@link EGLSurface}. + * @param height Height of the underlying {@link EGLSurface}. + * @param renderableType Bitmask indicating which types of client API contexts + * the framebuffer config must support. + */ + public EGLHelper(int width, int height, int renderableType) + { + // Initialize handle to an EGL display. + mEGL = (EGL10) EGLContext.getEGL(); + mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + // If a display is present, initialize EGL. + if (mDisplay != EGL10.EGL_NO_DISPLAY) + { + int[] version = new int[2]; + if (mEGL.eglInitialize(mDisplay, version)) + { + // Detect supported GL APIs, initialize configs, etc. + detect(); + + // Create context and surface + create(width, height, renderableType); + } + else + { + Log.e("EGLHelper", "Error initializing EGL."); + } + } + else + { + Log.e("EGLHelper", "Error initializing EGL display."); + } + } + + /** + * Releases all resources associated with this helper. + *

+ * This should be called whenever this helper is no longer needed. + */ + public void closeHelper() + { + mEGL.eglTerminate(mDisplay); + } + + /** + * Gets information through EGL.
+ *

+ * Index 0: Vendor
+ * Index 1: Renderer
+ * Index 2: Version
+ * Index 3: Extensions
+ * + * @return information retrieved through EGL. + */ + public String[] getEGLInfo() + { + String[] info = { + mGL.glGetString(GL10.GL_VENDOR), + mGL.glGetString(GL10.GL_RENDERER), + mGL.glGetString(GL10.GL_VERSION), + mGL.glGetString(GL10.GL_EXTENSIONS), + }; + + return info; + } + + /** + * Whether or not this device supports OpenGL. + * + * @return true if this device supports OpenGL; false otherwise. + */ + public boolean supportsOpenGL() + { + return supportGL; + } + + /** + * Whether or not this device supports OpenGL ES 2. + *
+ * Note that if this returns true, then OpenGL ES 1 is also supported. + * + * @return true if this device supports OpenGL ES 2; false otherwise. + */ + public boolean supportsGLES2() + { + return supportGLES2; + } + + /** + * Whether or not this device supports OpenGL ES 3. + *
+ * Note that if this returns true, then OpenGL ES 1 and 2 are also supported. + * + * @return true if this device supports OpenGL ES 3; false otherwise. + */ + public boolean supportsGLES3() + { + return supportGLES3; + } + + /** + * Gets the underlying {@link EGL10} instance. + * + * @return the underlying {@link EGL10} instance. + */ + public EGL10 getEGL() + { + return mEGL; + } + + /** + * Gets the underlying {@link GL10} instance. + * + * @return the underlying {@link GL10} instance. + */ + public GL10 getGL() + { + return mGL; + } + + /** + * Gets the underlying {@link EGLDisplay}. + * + * @return the underlying {@link EGLDisplay} + */ + public EGLDisplay getDisplay() + { + return mDisplay; + } + + /** + * Gets all supported framebuffer configurations for this device. + * + * @return all supported framebuffer configurations for this device. + */ + public EGLConfig[] getConfigs() + { + return mEGLConfigs; + } + + /** + * Gets the underlying {@link EGLContext}. + * + * @return the underlying {@link EGLContext}. + */ + public EGLContext getContext() + { + return mEGLContext; + } + + /** + * Gets the underlying {@link EGLSurface}. + * + * @return the underlying {@link EGLSurface}. + */ + public EGLSurface getSurface() + { + return mEGLSurface; + } + + // Detects the specific kind of GL modes that are supported + private boolean detect() + { + // Attributes for a visual in RGBA format with at least 8 bits per color. + int[] attribs = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_NONE + }; + + // Get total number of configs available. + int[] numConfigs = new int[1]; + if (!mEGL.eglChooseConfig(mDisplay, attribs, null, 0, numConfigs)) + { + Log.e("EGLHelper", "Error retrieving number of EGL configs available."); + return false; + } + + // Now get all the configurations + mEGLConfigs = new EGLConfig[numConfigs[0]]; + if (!mEGL.eglChooseConfig(mDisplay, attribs, mEGLConfigs, mEGLConfigs.length, numConfigs)) + { + Log.e("EGLHelper", "Error retrieving all EGL configs."); + return false; + } + + for (int i = 0; i < mEGLConfigs.length; i++) + { + int[] attribVal = new int[1]; + boolean ret = mEGL.eglGetConfigAttrib(mDisplay, mEGLConfigs[i], EGL10.EGL_RENDERABLE_TYPE, attribVal); + if (ret) + { + if ((attribVal[0] & EGL_OPENGL_BIT) != 0) + supportGL = true; + + if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0) + supportGLES2 = true; + + if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0) + supportGLES3 = true; + } + } + + return true; + } + + // Creates the context and surface. + private void create(int width, int height, int renderableType) + { + int[] attribs = { + EGL10.EGL_WIDTH, width, + EGL10.EGL_HEIGHT, height, + EGL10.EGL_RENDERABLE_TYPE, renderableType, + EGL10.EGL_NONE + }; + + // Initially we just assume GLES2 will be the default context. + int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + int[] ctx_attribs = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL10.EGL_NONE + }; + + // Determine the type of context that will be created + // and change the attribute arrays accordingly. + switch (renderableType) + { + case EGL_OPENGL_ES_BIT: + attribs[5] = EGL_OPENGL_ES_BIT; + ctx_attribs[1] = 1; + break; + + case EGL_OPENGL_BIT: + attribs[5] = EGL_OPENGL_BIT; + ctx_attribs[0] = EGL10.EGL_NONE; + break; + + case EGL_OPENGL_ES3_BIT_KHR: + attribs[5] = EGL_OPENGL_ES3_BIT_KHR; + ctx_attribs[1] = 3; + break; + + case EGL_OPENGL_ES2_BIT: + default: // Fall-back to GLES 2. + attribs[5] = EGL_OPENGL_ES2_BIT; + ctx_attribs[1] = 2; + break; + } + + mEGLContext = mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs); + mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs); + mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext); + mGL = (GL10) mEGLContext.getGL(); + } +}