* Safety first: *ALL* EGL calls are now checked for errors prior to proceeding
* Safety first. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10791 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
d70174d91a
commit
25814a8859
@ -3,23 +3,27 @@ package com.jme3.renderer.android;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLU;
|
||||
import com.jme3.renderer.RendererException;
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGL11;
|
||||
|
||||
/**
|
||||
* Utility class used by the {@link OGLESShaderRenderer renderer} and sister classes.
|
||||
*
|
||||
* Utility class used by the {@link OGLESShaderRenderer renderer} and sister
|
||||
* classes.
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class RendererUtil {
|
||||
|
||||
|
||||
/**
|
||||
* When set to true, every OpenGL call will check for errors and throw
|
||||
* an exception if there is one, if false, no error checking is performed.
|
||||
* When set to true, every OpenGL call will check for errors and throw an
|
||||
* exception if there is one, if false, no error checking is performed.
|
||||
*/
|
||||
public static boolean ENABLE_ERROR_CHECKING = true;
|
||||
|
||||
|
||||
/**
|
||||
* Checks for an OpenGL error and throws a {@link RendererException}
|
||||
* if there is one. Ignores the value of {@link RendererUtil#ENABLE_ERROR_CHECKING}.
|
||||
* Checks for an OpenGL error and throws a {@link RendererException} if
|
||||
* there is one. Ignores the value of
|
||||
* {@link RendererUtil#ENABLE_ERROR_CHECKING}.
|
||||
*/
|
||||
public static void checkGLErrorForced() {
|
||||
int error = GLES20.glGetError();
|
||||
@ -32,14 +36,86 @@ public class RendererUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks for an OpenGL error and throws a {@link RendererException}
|
||||
* if there is one. Does nothing if {@link RendererUtil#ENABLE_ERROR_CHECKING}
|
||||
* is set to <code>false</code>.
|
||||
* Checks for an EGL error and throws a {@link RendererException} if there
|
||||
* is one. Ignores the value of {@link RendererUtil#ENABLE_ERROR_CHECKING}.
|
||||
*/
|
||||
public static void checkEGLError(EGL10 egl) {
|
||||
int error = egl.eglGetError();
|
||||
if (error != EGL10.EGL_SUCCESS) {
|
||||
String errorMessage;
|
||||
switch (error) {
|
||||
case EGL10.EGL_SUCCESS:
|
||||
return;
|
||||
case EGL10.EGL_NOT_INITIALIZED:
|
||||
errorMessage = "EGL is not initialized, or could not be "
|
||||
+ "initialized, for the specified EGL display connection. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_ACCESS:
|
||||
errorMessage = "EGL cannot access a requested resource "
|
||||
+ "(for example a context is bound in another thread). ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_ALLOC:
|
||||
errorMessage = "EGL failed to allocate resources for the requested operation.";
|
||||
break;
|
||||
case EGL10.EGL_BAD_ATTRIBUTE:
|
||||
errorMessage = "An unrecognized attribute or attribute "
|
||||
+ "value was passed in the attribute list. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_CONTEXT:
|
||||
errorMessage = "An EGLContext argument does not name a valid EGL rendering context. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_CONFIG:
|
||||
errorMessage = "An EGLConfig argument does not name a valid EGL frame buffer configuration. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_CURRENT_SURFACE:
|
||||
errorMessage = "The current surface of the calling thread "
|
||||
+ "is a window, pixel buffer or pixmap that is no longer valid. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_DISPLAY:
|
||||
errorMessage = "An EGLDisplay argument does not name a valid EGL display connection. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_SURFACE:
|
||||
errorMessage = "An EGLSurface argument does not name a "
|
||||
+ "valid surface (window, pixel buffer or pixmap) configured for GL rendering. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_MATCH:
|
||||
errorMessage = "Arguments are inconsistent (for example, a "
|
||||
+ "valid context requires buffers not supplied by a valid surface). ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_PARAMETER:
|
||||
errorMessage = "One or more argument values are invalid.";
|
||||
break;
|
||||
case EGL10.EGL_BAD_NATIVE_PIXMAP:
|
||||
errorMessage = "A NativePixmapType argument does not refer to a valid native pixmap. ";
|
||||
break;
|
||||
case EGL10.EGL_BAD_NATIVE_WINDOW:
|
||||
errorMessage = "A NativeWindowType argument does not refer to a valid native window. ";
|
||||
break;
|
||||
case EGL11.EGL_CONTEXT_LOST:
|
||||
errorMessage = "A power management event has occurred. "
|
||||
+ "The application must destroy all contexts and reinitialise "
|
||||
+ "OpenGL ES state and objects to continue rendering. ";
|
||||
break;
|
||||
default:
|
||||
errorMessage = "Unknown";
|
||||
}
|
||||
|
||||
throw new RendererException("EGL error 0x" + Integer.toHexString(error) + ": " + errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for an OpenGL error and throws a {@link RendererException} if
|
||||
* there is one. Does nothing if {@link RendererUtil#ENABLE_ERROR_CHECKING}
|
||||
* is set to
|
||||
* <code>false</code>.
|
||||
*/
|
||||
public static void checkGLError() {
|
||||
if (!ENABLE_ERROR_CHECKING) return;
|
||||
if (!ENABLE_ERROR_CHECKING) {
|
||||
return;
|
||||
}
|
||||
int error = GLES20.glGetError();
|
||||
if (error != 0) {
|
||||
String message = GLU.gluErrorString(error);
|
||||
|
@ -2,6 +2,7 @@ package com.jme3.system.android;
|
||||
|
||||
import android.graphics.PixelFormat;
|
||||
import android.opengl.GLSurfaceView.EGLConfigChooser;
|
||||
import com.jme3.renderer.android.RendererUtil;
|
||||
import com.jme3.system.AppSettings;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -91,6 +92,15 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
private static int eglGetConfigAttribSafe(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute) {
|
||||
int[] value = new int[1];
|
||||
if (!egl.eglGetConfigAttrib(display, config, attribute, value)) {
|
||||
RendererUtil.checkEGLError(egl);
|
||||
throw new AssertionError();
|
||||
}
|
||||
return value[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called by the GLSurfaceView class to return the best config
|
||||
*/
|
||||
@ -130,17 +140,16 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
}
|
||||
|
||||
private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) {
|
||||
int[] value = new int[1];
|
||||
|
||||
//Android Pixel format is not very well documented.
|
||||
//From what i gathered, the format is chosen automatically except for the alpha channel
|
||||
//if the alpha channel has 8 bit or more, e set the pixel format to Transluscent, as it allow transparent view background
|
||||
//if it's 0 bit, the format is OPAQUE otherwise it's TRANSPARENT
|
||||
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value);
|
||||
if (value[0] >= 8) {
|
||||
int result = eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_ALPHA_SIZE);
|
||||
|
||||
if (result >= 8) {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
if (value[0] >= 1) {
|
||||
if (result >= 1) {
|
||||
return PixelFormat.TRANSPARENT;
|
||||
}
|
||||
|
||||
@ -148,29 +157,15 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
}
|
||||
|
||||
private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) {
|
||||
int[] value = new int[1];
|
||||
int result = 1;
|
||||
|
||||
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value);
|
||||
int val = eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_RENDERABLE_TYPE);
|
||||
// Check if conf is OpenGL ES 2.0
|
||||
if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) {
|
||||
result = 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void logEGLConfigAttrib (EGLConfig conf, EGLDisplay display, EGL10 egl,
|
||||
Level level, String configName, int eglConfigAttrib) {
|
||||
|
||||
int[] value = new int[1];
|
||||
if (egl.eglGetConfigAttrib(display, conf, eglConfigAttrib, value)) {
|
||||
logger.log(level, "{0} = {1}", new Object[]{configName, value[0]});
|
||||
if ((val & EGL_OPENGL_ES2_BIT) != 0) {
|
||||
return 2;
|
||||
} else {
|
||||
logger.log(level, "Error getting {0} = {1}",
|
||||
new Object[]{configName, egl.eglGetError()});
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* log output with egl config details
|
||||
*
|
||||
@ -179,25 +174,36 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
* @param egl
|
||||
*/
|
||||
public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl, Level level) {
|
||||
logger.log(level, "Logging EGLConfig Attributes");
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_RED_SIZE", EGL10.EGL_RED_SIZE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_GREEN_SIZE", EGL10.EGL_GREEN_SIZE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_BLUE_SIZE", EGL10.EGL_BLUE_SIZE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_RENDERABLE_TYPE", EGL10.EGL_RENDERABLE_TYPE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS);
|
||||
logEGLConfigAttrib(conf, display, egl, level,
|
||||
"EGL_SAMPLES", EGL10.EGL_SAMPLES);
|
||||
|
||||
logger.log(level, "EGL_RED_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_RED_SIZE));
|
||||
|
||||
logger.log(level, "EGL_GREEN_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_GREEN_SIZE));
|
||||
|
||||
logger.log(level, "EGL_BLUE_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_BLUE_SIZE));
|
||||
|
||||
logger.log(level, "EGL_ALPHA_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_ALPHA_SIZE));
|
||||
|
||||
logger.log(level, "EGL_DEPTH_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_DEPTH_SIZE));
|
||||
|
||||
logger.log(level, "EGL_STENCIL_SIZE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_STENCIL_SIZE));
|
||||
|
||||
logger.log(level, "EGL_RENDERABLE_TYPE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_RENDERABLE_TYPE));
|
||||
|
||||
logger.log(level, "EGL_SURFACE_TYPE = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_SURFACE_TYPE));
|
||||
|
||||
logger.log(level, "EGL_SAMPLE_BUFFERS = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_SAMPLE_BUFFERS));
|
||||
|
||||
logger.log(level, "EGL_SAMPLES = {0}",
|
||||
eglGetConfigAttribSafe(egl, display, conf, EGL10.EGL_SAMPLES));
|
||||
}
|
||||
|
||||
public int getClientOpenGLESVersion() {
|
||||
@ -225,11 +231,17 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE};
|
||||
|
||||
egl.eglChooseConfig(display, configSpec, null, 0, num_config);
|
||||
if (!egl.eglChooseConfig(display, configSpec, null, 0, num_config)) {
|
||||
RendererUtil.checkEGLError(egl);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
int numConfigs = num_config[0];
|
||||
EGLConfig[] configs = new EGLConfig[numConfigs];
|
||||
egl.eglChooseConfig(display, configSpec, configs, numConfigs, num_config);
|
||||
if (!egl.eglChooseConfig(display, configSpec, configs, numConfigs, num_config)) {
|
||||
RendererUtil.checkEGLError(egl);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
logger.fine("--------------Display Configurations---------------");
|
||||
for (EGLConfig eGLConfig : configs) {
|
||||
@ -251,12 +263,10 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
*/
|
||||
private class ComponentSizeChooser extends BaseConfigChooser {
|
||||
|
||||
private int[] mValue;
|
||||
private ConfigType configType;
|
||||
protected int mSamples;
|
||||
|
||||
public ComponentSizeChooser(ConfigType configType, int samples) {
|
||||
mValue = new int[1];
|
||||
mSamples = samples;
|
||||
this.configType = configType;
|
||||
}
|
||||
@ -271,22 +281,22 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
|
||||
// first pass through config list. Try to find an exact match.
|
||||
for (EGLConfig config : configs) {
|
||||
int r = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_RED_SIZE, 0);
|
||||
int g = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_GREEN_SIZE, 0);
|
||||
int b = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_BLUE_SIZE, 0);
|
||||
int a = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_ALPHA_SIZE, 0);
|
||||
int d = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_DEPTH_SIZE, 0);
|
||||
int s = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_STENCIL_SIZE, 0);
|
||||
int isMs = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_SAMPLE_BUFFERS, 0);
|
||||
int nbMs = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_SAMPLES, 0);
|
||||
int r = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_RED_SIZE);
|
||||
int g = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_GREEN_SIZE);
|
||||
int b = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_BLUE_SIZE);
|
||||
int a = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_ALPHA_SIZE);
|
||||
int d = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_DEPTH_SIZE);
|
||||
int s = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_STENCIL_SIZE);
|
||||
int isMs = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_SAMPLE_BUFFERS);
|
||||
int nbMs = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_SAMPLES);
|
||||
|
||||
if (inRange(r, configType.mr, configType.r)
|
||||
&& inRange(g, configType.mg, configType.g)
|
||||
@ -348,8 +358,8 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
|
||||
// failsafe. pick the 1st config with a 16 bit depth buffer.
|
||||
for (EGLConfig config : configs) {
|
||||
int d = findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_DEPTH_SIZE, 0);
|
||||
int d = eglGetConfigAttribSafe(egl, display, config,
|
||||
EGL10.EGL_DEPTH_SIZE);
|
||||
if (d >= 16) {
|
||||
return config;
|
||||
}
|
||||
@ -362,15 +372,6 @@ public class AndroidConfigChooser implements EGLConfigChooser {
|
||||
private boolean inRange(int val, int min, int max) {
|
||||
return min <= val && val <= max;
|
||||
}
|
||||
|
||||
private int findConfigAttrib(EGL10 egl, EGLDisplay display,
|
||||
EGLConfig config, int attribute, int defaultValue) {
|
||||
|
||||
if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
|
||||
return mValue[0];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
//DON'T REMOVE THIS, USED FOR UNIT TESTING FAILING CONFIGURATION LISTS.
|
||||
// private static class Config {
|
||||
|
@ -48,7 +48,9 @@ import com.jme3.input.android.AndroidSensorJoyInput;
|
||||
import com.jme3.input.controls.SoftTextDialogInputListener;
|
||||
import com.jme3.input.dummy.DummyKeyInput;
|
||||
import com.jme3.input.dummy.DummyMouseInput;
|
||||
import com.jme3.renderer.RendererException;
|
||||
import com.jme3.renderer.android.OGLESShaderRenderer;
|
||||
import com.jme3.renderer.android.RendererUtil;
|
||||
import com.jme3.system.*;
|
||||
import com.jme3.system.android.AndroidConfigChooser.ConfigType;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -145,11 +147,16 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
} else {
|
||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
int[] version = new int[2];
|
||||
if (egl.eglInitialize(display, version) == true) {
|
||||
logger.log(Level.INFO, "Display EGL Version: {0}.{1}", new Object[]{version[0], version[1]});
|
||||
if (display == EGL10.EGL_NO_DISPLAY) {
|
||||
throw new RendererException("No default EGL display is available");
|
||||
}
|
||||
|
||||
int[] version = new int[2];
|
||||
if (!egl.eglInitialize(display, version)) {
|
||||
RendererUtil.checkEGLError(egl);
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "Display EGL Version: {0}.{1}", new Object[]{version[0], version[1]});
|
||||
|
||||
try {
|
||||
// Create a config chooser
|
||||
@ -172,7 +179,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
view.setEGLConfigChooser(configChooser);
|
||||
view.getHolder().setFormat(configChooser.getPixelFormat());
|
||||
} finally {
|
||||
if (display != null) {
|
||||
if (display != null && display != EGL10.EGL_NO_DISPLAY) {
|
||||
egl.eglTerminate(display);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user