aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Lees2010-10-25 08:50:16 +0000
committerAngus Lees2010-10-25 08:50:16 +0000
commit3bd60b09c1b58a2a75591d89a806d6f0d1b1221c (patch)
tree89461a4ac39a64c05d5d0ffd2bb93891091dcd0e
parentf158688c33a07bbb9eb6351a6b03d27bcebe6eb7 (diff)
downloadscummvm-rg350-3bd60b09c1b58a2a75591d89a806d6f0d1b1221c.tar.gz
scummvm-rg350-3bd60b09c1b58a2a75591d89a806d6f0d1b1221c.tar.bz2
scummvm-rg350-3bd60b09c1b58a2a75591d89a806d6f0d1b1221c.zip
ANDROID: Don't trust eglChooseConfig and refilter/sort results manually
It seems some Android versions and devices (eg Droid) don't implement eglChooseConfig according to spec and the first result isn't the best choice. Implement our own filtering / scoring to workaround this. svn-id: r53808
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVM.java123
1 files changed, 118 insertions, 5 deletions
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index d39aa363ef..6986f3988d 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -23,6 +23,8 @@ import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
import java.util.concurrent.Semaphore;
+import java.util.Map;
+import java.util.LinkedHashMap;
// At least in Android 2.1, eglCreateWindowSurface() requires an
@@ -109,6 +111,51 @@ public class ScummVM implements SurfaceHolder.Callback {
}
}
+ // For debugging
+ private static final Map<String, Integer> attribs;
+ static {
+ attribs = new LinkedHashMap<String, Integer>();
+ attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID);
+ attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE);
+ attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE);
+ attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE);
+ attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE);
+ attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE);
+ //attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB);
+ //attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA);
+ attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT);
+ attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE);
+ attribs.put("LEVEL", EGL10.EGL_LEVEL);
+ attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH);
+ attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT);
+ attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS);
+ //attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL);
+ //attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL);
+ attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE);
+ attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID);
+ attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE);
+ attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS);
+ attribs.put("SAMPLES", EGL10.EGL_SAMPLES);
+ attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE);
+ attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE);
+ attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE);
+ attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE);
+ attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE);
+ attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE);
+ }
+ private void dumpEglConfig(EGLConfig config) {
+ int[] value = new int[1];
+ for (Map.Entry<String, Integer> entry : attribs.entrySet()) {
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ entry.getValue(), value);
+ if (value[0] == EGL10.EGL_NONE)
+ Log.d(LOG_TAG, entry.getKey() + ": NONE");
+ else
+ Log.d(LOG_TAG, String.format("%s: %d",
+ entry.getKey(), value[0]));
+ }
+ }
+
// Called by ScummVM thread (from initBackend)
private void createScummVMGLContext() {
egl = (EGL10)EGLContext.getEGL();
@@ -125,10 +172,75 @@ public class ScummVM implements SurfaceHolder.Callback {
EGLConfig[] configs = new EGLConfig[numConfigs];
egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs,
num_config);
- eglConfig = configs[0];
+
+ if (false) {
+ Log.d(LOG_TAG,
+ String.format("Found %d EGL configurations.", numConfigs));
+ for (EGLConfig config : configs)
+ dumpEglConfig(config);
+ }
+
+ // Android's eglChooseConfig is busted in several versions and
+ // devices so we have to filter/rank the configs again ourselves.
+ eglConfig = chooseEglConfig(configs);
+ if (false) {
+ Log.d(LOG_TAG,
+ String.format("Chose EGL config from %d possibilities.", numConfigs));
+ dumpEglConfig(eglConfig);
+ }
eglContext = egl.eglCreateContext(eglDisplay, eglConfig,
EGL10.EGL_NO_CONTEXT, null);
+ if (eglContext == EGL10.EGL_NO_CONTEXT)
+ throw new RuntimeException("Failed to create context");
+ }
+
+ private EGLConfig chooseEglConfig(EGLConfig[] configs) {
+ int best = 0;
+ int bestScore = -1;
+ int[] value = new int[1];
+ for (int i = 0; i < configs.length; i++) {
+ EGLConfig config = configs[i];
+ int score = 10000;
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_SURFACE_TYPE, value);
+ if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0)
+ continue; // must have
+
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_CONFIG_CAVEAT, value);
+ if (value[0] != EGL10.EGL_NONE)
+ score -= 1000;
+
+ // Must be at least 555, but then smaller is better
+ final int[] colorBits = {EGL10.EGL_RED_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_ALPHA_SIZE};
+ for (int component : colorBits) {
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ component, value);
+ if (value[0] >= 5)
+ score += 10; // boost if >5 bits accuracy
+ score -= value[0]; // penalize for wasted bits
+ }
+
+ egl.eglGetConfigAttrib(eglDisplay, config,
+ EGL10.EGL_DEPTH_SIZE, value);
+ score -= value[0]; // penalize for wasted bits
+
+ if (score > bestScore) {
+ best = i;
+ bestScore = score;
+ }
+ }
+
+ if (bestScore < 0) {
+ Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness.");
+ return configs[0];
+ }
+
+ return configs[best];
}
// Called by ScummVM thread
@@ -137,12 +249,13 @@ public class ScummVM implements SurfaceHolder.Callback {
try {
surfaceLock.acquire();
} catch (InterruptedException e) {
- Log.e(this.toString(),
- "Interrupted while waiting for surface lock", e);
+ Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e);
return;
}
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig,
nativeSurface, null);
+ if (eglSurface == EGL10.EGL_NO_SURFACE)
+ Log.e(LOG_TAG, "CreateWindowSurface failed!");
egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
GL10 gl = (GL10)eglContext.getGL();
@@ -302,8 +415,8 @@ public class ScummVM implements SurfaceHolder.Callback {
if (buf_size < 0) {
int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio
Log.w(LOG_TAG, String.format(
- "Unable to get min audio buffer size (error %d). Guessing %dB.",
- buf_size, guess));
+ "Unable to get min audio buffer size (error %d). Guessing %dB.",
+ buf_size, guess));
buf_size = guess;
}
Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio",