1 package org.ppsspp.ppsspp;
2 
3 import android.opengl.GLSurfaceView.EGLConfigChooser;
4 import android.util.Log;
5 import javax.microedition.khronos.egl.EGL10;
6 import javax.microedition.khronos.egl.EGLConfig;
7 import javax.microedition.khronos.egl.EGLDisplay;
8 
9 public class NativeEGLConfigChooser implements EGLConfigChooser {
10 	private static final String TAG = "NativeEGLConfigChooser";
11 
12 	private static final int EGL_OPENGL_ES2_BIT = 4;
13 
14 	NativeEGLConfigChooser() {
init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalStorageDir, String extFilesDir, String additionalStorageDirs, String libraryDir, String cacheDir, String shortcutParam, int androidVersion, String board)15 	}
16 
17 	private class ConfigAttribs {
18 		EGLConfig config;
19 		public int red;
20 		public int green;
21 		public int blue;
22 		public int alpha;
23 		public int stencil;
24 		public int depth;
25 		public int samples;
26 
27 		public void Log() {
28 			Log.i(TAG, "EGLConfig: red=" + red + " green=" + green + " blue=" + blue + " alpha=" + alpha + " depth=" + depth + " stencil=" + stencil + " samples=" + samples);
29 		}
30 	}
isLandscape()31 
32 	int getEglConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attr) {
33 		int[] value = new int[1];
34 		try {
35 			if (egl.eglGetConfigAttrib(display, config, attr, value))
36 				return value[0];
37 			else
38 				return -1;
39 		} catch (IllegalArgumentException e) {
40 			if (config == null) {
41 				Log.e(TAG, "Called getEglConfigAttrib with null config. Bad developer.");
42 			} else {
43 				Log.e(TAG, "Illegal argument to getEglConfigAttrib: attr=" + attr);
44 			}
45 			return -1;
46 		}
47 	}
48 
49 	ConfigAttribs[] getConfigAttribs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
touch(float x, float y, int data, int pointerId)50 		ConfigAttribs[] attr = new ConfigAttribs[configs.length];
51 		for (int i = 0; i < configs.length; i++) {
accelerometer(float x, float y, float z)52 			ConfigAttribs cfg = new ConfigAttribs();
53 			cfg.config = configs[i];
sendMessage(String msg, String arg)54 			cfg.red = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE);
sendInputBox(String seqID, boolean result, String value)55 			cfg.green = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_GREEN_SIZE);
56 			cfg.blue = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_BLUE_SIZE);
queryConfig(String queryName)57 			cfg.alpha = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE);
58 			cfg.depth = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE);
getSelectedCamera()59 			cfg.stencil = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_STENCIL_SIZE);
setGpsDataAndroid(long time, float hdop, float latitude, float longitude, float altitude, float speed, float bearing)60 			cfg.samples = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_SAMPLES);
setSatInfoAndroid(short index, short id, short elevation, short azimuth, short snr, short good)61 			attr[i] = cfg;
pushCameraImageAndroid(byte[] image)62 		}
63 		return attr;
64 	}
65 
66 	@Override
67 	public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
68 		// The absolute minimum. We will do our best to choose a better config though.
69 		int[] configSpec = {
70 			EGL10.EGL_RED_SIZE, 5,
71 			EGL10.EGL_GREEN_SIZE, 6,
72 			EGL10.EGL_BLUE_SIZE, 5,
73 			EGL10.EGL_DEPTH_SIZE, 16,
74 			EGL10.EGL_STENCIL_SIZE, 0,
75 			EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
76 			EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
77 			// EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_NONE
78 			EGL10.EGL_NONE
79 		};
80 
81 		int[] num_config = new int[1];
82 		if (!egl.eglChooseConfig(display, configSpec, null, 0, num_config)) {
83 			throw new IllegalArgumentException("eglChooseConfig failed when counting");
84 		}
85 
86 		int numConfigs = num_config[0];
87 		Log.i(TAG, "There are " + numConfigs + " egl configs");
88 		if (numConfigs <= 0) {
89 			throw new IllegalArgumentException("No configs match configSpec");
90 		}
91 
92 		EGLConfig[] eglConfigs = new EGLConfig[numConfigs];
93 		if (!egl.eglChooseConfig(display, configSpec, eglConfigs, numConfigs, num_config)) {
94 			throw new IllegalArgumentException("eglChooseConfig failed when retrieving");
95 		}
96 
97 		ConfigAttribs[] configs = getConfigAttribs(egl, display, eglConfigs);
98 
99 		ConfigAttribs chosen = null;
100 
101 		// Log them all.
102 		for (int i = 0; i < configs.length; i++) {
103 			configs[i].Log();
104 		}
105 
106 		// We now ignore destination alpha as a workaround for the Mali issue
107 		// where we get badly composited if we use it.
108 		// Though, that may be possible to fix by using EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_NONE.
109 
110 		// First, find our ideal configuration. Prefer depth.
111 		for (int i = 0; i < configs.length; i++) {
112 			ConfigAttribs c = configs[i];
113 			if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 24) {
114 				chosen = c;
115 				break;
116 			}
117 		}
118 
119 		if (chosen == null) {
120 			// Then, prefer one with 20-bit depth (Tegra 3)
121 			for (int i = 0; i < configs.length; i++) {
122 				ConfigAttribs c = configs[i];
123 				if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 20) {
124 					chosen = c;
125 					break;
126 				}
127 			}
128 		}
129 
130 		if (chosen == null) {
131 			// Second, accept one with 16-bit depth.
132 			for (int i = 0; i < configs.length; i++) {
133 				ConfigAttribs c = configs[i];
134 				if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 16) {
135 					chosen = c;
136 					break;
137 				}
138 			}
139 		}
140 
141 		if (chosen == null) {
142 			// Third, accept one with no stencil.
143 			for (int i = 0; i < configs.length; i++) {
144 				ConfigAttribs c = configs[i];
145 				if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.depth >= 16) {
146 					chosen = c;
147 					break;
148 				}
149 			}
150 		}
151 
152 		if (chosen == null) {
153 			// Third, accept one with alpha but with stencil, 24-bit depth.
154 			for (int i = 0; i < configs.length; i++) {
155 				ConfigAttribs c = configs[i];
156 				if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 24) {
157 					chosen = c;
158 					break;
159 				}
160 			}
161 		}
162 
163 		if (chosen == null) {
164 			// Third, accept one with alpha but with stencil, 16-bit depth.
165 			for (int i = 0; i < configs.length; i++) {
166 				ConfigAttribs c = configs[i];
167 				if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 16) {
168 					chosen = c;
169 					break;
170 				}
171 			}
172 		}
173 
174 		if (chosen == null) {
175 			// Fourth, accept one with 16-bit color but depth and stencil required.
176 			for (int i = 0; i < configs.length; i++) {
177 				ConfigAttribs c = configs[i];
178 				if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16 && c.stencil >= 8) {
179 					chosen = c;
180 					break;
181 				}
182 			}
183 		}
184 
185 		if (chosen == null) {
186 			// Fifth, accept one with 16-bit color but depth required.
187 			for (int i = 0; i < configs.length; i++) {
188 				ConfigAttribs c = configs[i];
189 				if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16) {
190 					chosen = c;
191 					break;
192 				}
193 			}
194 		}
195 
196 		if (chosen == null) {
197 			// Final, accept the first one in the list.
198 			if (configs.length > 0)
199 				chosen = configs[0];
200 		}
201 
202 		if (chosen == null) {
203 			throw new IllegalArgumentException("Failed to find a valid EGL config");
204 		}
205 
206 		Log.i(TAG, "Final chosen config: ");
207 		chosen.Log();
208 		return chosen.config;
209 	}
210 }
211