1package com.jme3.system.android; 2 3import android.graphics.PixelFormat; 4import android.opengl.GLSurfaceView.EGLConfigChooser; 5import java.util.logging.Level; 6import java.util.logging.Logger; 7import javax.microedition.khronos.egl.EGL10; 8import javax.microedition.khronos.egl.EGLConfig; 9import javax.microedition.khronos.egl.EGLDisplay; 10 11/** 12 * AndroidConfigChooser is used to determine the best suited EGL Config 13 * 14 * @author larynx 15 */ 16public class AndroidConfigChooser implements EGLConfigChooser { 17 18 private static final Logger logger = Logger.getLogger(AndroidConfigChooser.class.getName()); 19 protected int clientOpenGLESVersion = 0; 20 protected EGLConfig bestConfig = null; 21 protected EGLConfig fastestConfig = null; 22 protected EGLConfig choosenConfig = null; 23 protected ConfigType type; 24 protected int pixelFormat; 25 protected boolean verbose = false; 26 private final static int EGL_OPENGL_ES2_BIT = 4; 27 28 public enum ConfigType { 29 30 /** 31 * RGB565, 0 alpha, 16 depth, 0 stencil 32 */ 33 FASTEST, 34 /** 35 * RGB???, 0 alpha, >=16 depth, 0 stencil 36 */ 37 BEST, 38 /** 39 * Turn off config chooser and use hardcoded 40 * setEGLContextClientVersion(2); setEGLConfigChooser(5, 6, 5, 0, 16, 41 * 0); 42 */ 43 LEGACY 44 } 45 46 public AndroidConfigChooser(ConfigType type) { 47 this.type = type; 48 } 49 50 /** 51 * Gets called by the GLSurfaceView class to return the best config 52 */ 53 @Override 54 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 55 logger.info("GLSurfaceView asks for egl config, returning: "); 56 logEGLConfig(choosenConfig, display, egl); 57 return choosenConfig; 58 } 59 60 /** 61 * findConfig is used to locate the best config and init the chooser with 62 * 63 * @param egl 64 * @param display 65 * @return true if successfull, false if no config was found 66 */ 67 public boolean findConfig(EGL10 egl, EGLDisplay display) { 68 69 if (type == ConfigType.BEST) { 70 ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0); 71 choosenConfig = compChooser.chooseConfig(egl, display); 72 73 if (choosenConfig == null) { 74 compChooser = new ComponentSizeChooser(8, 8, 8, 0, 32, 0); 75 choosenConfig = compChooser.chooseConfig(egl, display); 76 if (choosenConfig == null) { 77 compChooser = new ComponentSizeChooser(8, 8, 8, 8, 16, 0); 78 choosenConfig = compChooser.chooseConfig(egl, display); 79 if (choosenConfig == null) { 80 compChooser = new ComponentSizeChooser(8, 8, 8, 0, 16, 0); 81 choosenConfig = compChooser.chooseConfig(egl, display); 82 } 83 } 84 } 85 86 logger.info("JME3 using best EGL configuration available here: "); 87 } else { 88 ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0); 89 choosenConfig = compChooser.chooseConfig(egl, display); 90 logger.info("JME3 using fastest EGL configuration available here: "); 91 } 92 93 if (choosenConfig != null) { 94 logger.info("JME3 using choosen config: "); 95 logEGLConfig(choosenConfig, display, egl); 96 pixelFormat = getPixelFormat(choosenConfig, display, egl); 97 clientOpenGLESVersion = getOpenGLVersion(choosenConfig, display, egl); 98 return true; 99 } else { 100 logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this."); 101 clientOpenGLESVersion = 1; 102 pixelFormat = PixelFormat.UNKNOWN; 103 return false; 104 } 105 } 106 107 private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) { 108 int[] value = new int[1]; 109 int result = PixelFormat.RGB_565; 110 111 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); 112 if (value[0] == 8) { 113 result = PixelFormat.RGBA_8888; 114 /* 115 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); 116 if (value[0] == 8) 117 { 118 result = PixelFormat.RGBA_8888; 119 } 120 else 121 { 122 result = PixelFormat.RGB_888; 123 }*/ 124 } 125 126 if (verbose) { 127 logger.log(Level.INFO, "Using PixelFormat {0}", result); 128 } 129 130 //return result; TODO Test pixelformat 131 return PixelFormat.TRANSPARENT; 132 } 133 134 private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) { 135 int[] value = new int[1]; 136 int result = 1; 137 138 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); 139 // Check if conf is OpenGL ES 2.0 140 if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) { 141 result = 2; 142 } 143 144 return result; 145 } 146 147 /** 148 * log output with egl config details 149 * 150 * @param conf 151 * @param display 152 * @param egl 153 */ 154 public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) { 155 int[] value = new int[1]; 156 157 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); 158 logger.info(String.format("EGL_RED_SIZE = %d", value[0])); 159 160 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value); 161 logger.info(String.format("EGL_GREEN_SIZE = %d", value[0])); 162 163 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value); 164 logger.info(String.format("EGL_BLUE_SIZE = %d", value[0])); 165 166 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); 167 logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0])); 168 169 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value); 170 logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0])); 171 172 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value); 173 logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0])); 174 175 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); 176 logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0])); 177 178 egl.eglGetConfigAttrib(display, conf, EGL10.EGL_SURFACE_TYPE, value); 179 logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0])); 180 } 181 182 public int getClientOpenGLESVersion() { 183 return clientOpenGLESVersion; 184 } 185 186 public void setClientOpenGLESVersion(int clientOpenGLESVersion) { 187 this.clientOpenGLESVersion = clientOpenGLESVersion; 188 } 189 190 public int getPixelFormat() { 191 return pixelFormat; 192 } 193 194 private abstract class BaseConfigChooser implements EGLConfigChooser { 195 196 private boolean bClientOpenGLESVersionSet; 197 198 public BaseConfigChooser(int[] configSpec) { 199 bClientOpenGLESVersionSet = false; 200 mConfigSpec = filterConfigSpec(configSpec); 201 } 202 203 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 204 int[] num_config = new int[1]; 205 if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, 206 num_config)) { 207 throw new IllegalArgumentException("eglChooseConfig failed"); 208 } 209 210 int numConfigs = num_config[0]; 211 212 if (numConfigs <= 0) { 213 //throw new IllegalArgumentException("No configs match configSpec"); 214 215 return null; 216 } 217 218 EGLConfig[] configs = new EGLConfig[numConfigs]; 219 if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, 220 num_config)) { 221 throw new IllegalArgumentException("eglChooseConfig#2 failed"); 222 } 223 EGLConfig config = chooseConfig(egl, display, configs); 224 //if (config == null) { 225 // throw new IllegalArgumentException("No config chosen"); 226 //} 227 return config; 228 } 229 230 abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 231 EGLConfig[] configs); 232 protected int[] mConfigSpec; 233 234 private int[] filterConfigSpec(int[] configSpec) { 235 if (bClientOpenGLESVersionSet == true) { 236 return configSpec; 237 } 238 /* 239 * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we 240 * know the configSpec is well formed. 241 */ 242 int len = configSpec.length; 243 int[] newConfigSpec = new int[len + 2]; 244 System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1); 245 newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE; 246 newConfigSpec[len] = 4; /* 247 * EGL_OPENGL_ES2_BIT 248 */ 249 newConfigSpec[len + 1] = EGL10.EGL_NONE; 250 251 bClientOpenGLESVersionSet = true; 252 253 return newConfigSpec; 254 } 255 } 256 257 /** 258 * Choose a configuration with exactly the specified r,g,b,a sizes, and at 259 * least the specified depth and stencil sizes. 260 */ 261 private class ComponentSizeChooser extends BaseConfigChooser { 262 263 private int[] mValue; 264 // Subclasses can adjust these values: 265 protected int mRedSize; 266 protected int mGreenSize; 267 protected int mBlueSize; 268 protected int mAlphaSize; 269 protected int mDepthSize; 270 protected int mStencilSize; 271 272 public ComponentSizeChooser(int redSize, int greenSize, int blueSize, 273 int alphaSize, int depthSize, int stencilSize) { 274 super(new int[]{ 275 EGL10.EGL_RED_SIZE, redSize, 276 EGL10.EGL_GREEN_SIZE, greenSize, 277 EGL10.EGL_BLUE_SIZE, blueSize, 278 EGL10.EGL_ALPHA_SIZE, alphaSize, 279 EGL10.EGL_DEPTH_SIZE, depthSize, 280 EGL10.EGL_STENCIL_SIZE, stencilSize, 281 EGL10.EGL_NONE}); 282 mValue = new int[1]; 283 mRedSize = redSize; 284 mGreenSize = greenSize; 285 mBlueSize = blueSize; 286 mAlphaSize = alphaSize; 287 mDepthSize = depthSize; 288 mStencilSize = stencilSize; 289 } 290 291 @Override 292 public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { 293 for (EGLConfig config : configs) { 294 int d = findConfigAttrib(egl, display, config, 295 EGL10.EGL_DEPTH_SIZE, 0); 296 int s = findConfigAttrib(egl, display, config, 297 EGL10.EGL_STENCIL_SIZE, 0); 298 if ((d >= mDepthSize) && (s >= mStencilSize)) { 299 int r = findConfigAttrib(egl, display, config, 300 EGL10.EGL_RED_SIZE, 0); 301 int g = findConfigAttrib(egl, display, config, 302 EGL10.EGL_GREEN_SIZE, 0); 303 int b = findConfigAttrib(egl, display, config, 304 EGL10.EGL_BLUE_SIZE, 0); 305 int a = findConfigAttrib(egl, display, config, 306 EGL10.EGL_ALPHA_SIZE, 0); 307 if ((r == mRedSize) && (g == mGreenSize) 308 && (b == mBlueSize) && (a == mAlphaSize)) { 309 return config; 310 } 311 } 312 } 313 return null; 314 } 315 316 private int findConfigAttrib(EGL10 egl, EGLDisplay display, 317 EGLConfig config, int attribute, int defaultValue) { 318 319 if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 320 return mValue[0]; 321 } 322 return defaultValue; 323 } 324 } 325} 326