1 package com.jme3.system.android;
2 
3 import android.graphics.PixelFormat;
4 import android.opengl.GLSurfaceView.EGLConfigChooser;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7 import javax.microedition.khronos.egl.EGL10;
8 import javax.microedition.khronos.egl.EGLConfig;
9 import javax.microedition.khronos.egl.EGLDisplay;
10 
11 /**
12  * AndroidConfigChooser is used to determine the best suited EGL Config
13  *
14  * @author larynx
15  */
16 public 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 
AndroidConfigChooser(ConfigType type)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
chooseConfig(EGL10 egl, EGLDisplay display)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      */
findConfig(EGL10 egl, EGLDisplay display)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 
getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl)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 
getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl)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      */
logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl)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 
getClientOpenGLESVersion()182     public int getClientOpenGLESVersion() {
183         return clientOpenGLESVersion;
184     }
185 
setClientOpenGLESVersion(int clientOpenGLESVersion)186     public void setClientOpenGLESVersion(int clientOpenGLESVersion) {
187         this.clientOpenGLESVersion = clientOpenGLESVersion;
188     }
189 
getPixelFormat()190     public int getPixelFormat() {
191         return pixelFormat;
192     }
193 
194     private abstract class BaseConfigChooser implements EGLConfigChooser {
195 
196         private boolean bClientOpenGLESVersionSet;
197 
BaseConfigChooser(int[] configSpec)198         public BaseConfigChooser(int[] configSpec) {
199             bClientOpenGLESVersionSet = false;
200             mConfigSpec = filterConfigSpec(configSpec);
201         }
202 
chooseConfig(EGL10 egl, EGLDisplay display)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 
chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)230         abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
231                 EGLConfig[] configs);
232         protected int[] mConfigSpec;
233 
filterConfigSpec(int[] configSpec)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 
ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)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
chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)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 
findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue)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