[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.

This commit is contained in:
Lioncash 2014-01-19 18:29:43 -05:00
parent 45964e4b46
commit f8abdbf91a

View File

@ -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.
* <p>
* This should be called whenever this helper is no longer needed.
*/
public void closeHelper()
{
mEGL.eglTerminate(mDisplay);
}
/**
* Gets information through EGL.<br/>
* <p>
* Index 0: Vendor <br/>
* Index 1: Renderer <br/>
* Index 2: Version <br/>
* Index 3: Extensions <br/>
*
* @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.
* <br/>
* 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.
* <br/>
* 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();
}
}