aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/platform/android/README.build28
-rw-r--r--backends/platform/android/android.cpp84
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVM.java129
-rwxr-xr-xconfigure2
4 files changed, 117 insertions, 126 deletions
diff --git a/backends/platform/android/README.build b/backends/platform/android/README.build
index 0aa5c6eefd..3d1cf433a7 100644
--- a/backends/platform/android/README.build
+++ b/backends/platform/android/README.build
@@ -2,9 +2,8 @@ Building the ScummVM Android port
=================================
You will need these things to build:
-1. Android EGL headers and library
-2. Android SDK
-3. An arm-oe-linux-androideabi GCC toolchain(*)
+1. Android SDK
+2. An arm-oe-linux-androideabi GCC toolchain(*)
In the example commands, we are going to build against the Android 1.5
native ABI (but using the Android 1.6 SDK tools). Other version
@@ -18,21 +17,13 @@ you have some other prefix variation.
In detail:
-1. Android EGL headers and library
+1. Android SDK
-You can build these from the full Android source, but it is far easier
-to just download the 3 Android EGL headers from here:
- http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=opengl/include/EGL;hb=HEAD
- (copy them to a directory called "EGL" somewhere)
+Download the SDK from http://developer.android.com/ and install
+somewhere. You will need both the API level 8 (aka Android 2.2) and
+API level 3 (aka Android 1.5) platforms.
-... and grab libEGL.so off an existing phone/emulator:
- adb pull /system/lib/libEGL.so /tmp
-
-2. Android SDK
-
-Download and install somewhere.
-
-3. arm-*-linux-androideabi GCC toolchain
+2. arm-*-linux-androideabi GCC toolchain
You have several choices for toolchains:
@@ -95,11 +86,6 @@ Then build ScummVM:
export ANDROID_TOP=<root of built Android source>
- EGL_INC="-I<location of EGL/ header directory>"
- EGL_LIBS="-L<location of libEGL.so>"
-
- CPPFLAGS="$EGL_INC" \
- LDFLAGS="-g $EGL_LIBS" \
./configure --backend=android --host=android --enable-zlib #and any other flags
make scummvm.apk
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 105561e595..f6af0fcff5 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -41,7 +41,6 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
-#include <EGL/egl.h>
#include <android/log.h>
#include "common/archive.h"
@@ -166,12 +165,11 @@ private:
jmethodID MID_getPluginDirectories;
jmethodID MID_setupScummVMSurface;
jmethodID MID_destroyScummVMSurface;
+ jmethodID MID_swapBuffers;
int _screen_changeid;
- EGLDisplay _egl_display;
- EGLSurface _egl_surface;
- EGLint _egl_surface_width;
- EGLint _egl_surface_height;
+ int _egl_surface_width;
+ int _egl_surface_height;
bool _force_redraw;
@@ -223,6 +221,10 @@ public:
virtual void initBackend();
void addPluginDirectories(Common::FSList &dirs) const;
void enableZoning(bool enable) { _enable_zoning = enable; }
+ void setSurfaceSize(int width, int height) {
+ _egl_surface_width = width;
+ _egl_surface_height = height;
+ }
virtual bool hasFeature(Feature f);
virtual void setFeatureState(Feature f, bool enable);
@@ -303,8 +305,6 @@ public:
OSystem_Android::OSystem_Android(jobject am)
: _back_ptr(0),
- _egl_display(EGL_NO_DISPLAY),
- _egl_surface(EGL_NO_SURFACE),
_screen_changeid(0),
_force_redraw(false),
_game_texture(NULL),
@@ -369,6 +369,7 @@ bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) {
FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;");
FIND_METHOD(setupScummVMSurface, "()V");
FIND_METHOD(destroyScummVMSurface, "()V");
+ FIND_METHOD(swapBuffers, "()Z");
#undef FIND_METHOD
@@ -581,6 +582,7 @@ int OSystem_Android::getGraphicsMode() const {
}
void OSystem_Android::setupScummVMSurface() {
+ ENTER("setupScummVMSurface");
JNIEnv* env = JNU_GetEnv();
env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface);
if (env->ExceptionCheck())
@@ -588,37 +590,8 @@ void OSystem_Android::setupScummVMSurface() {
// EGL set up with a new surface. Initialise OpenGLES context.
- _egl_display = eglGetCurrentDisplay();
- _egl_surface = eglGetCurrentSurface(EGL_DRAW);
-
- static bool log_version = true;
- if (log_version) {
- __android_log_print(ANDROID_LOG_INFO, LOG_TAG,
- "Using EGL %s (%s); GL %s/%s (%s)",
- eglQueryString(_egl_display, EGL_VERSION),
- eglQueryString(_egl_display, EGL_VENDOR),
- glGetString(GL_VERSION),
- glGetString(GL_RENDERER),
- glGetString(GL_VENDOR));
- log_version = false; // only log this once
- }
-
GLESTexture::initGLExtensions();
- if (!eglQuerySurface(_egl_display, _egl_surface,
- EGL_WIDTH, &_egl_surface_width) ||
- !eglQuerySurface(_egl_display, _egl_surface,
- EGL_HEIGHT, &_egl_surface_height)) {
- JNU_ThrowByName(env, "java/lang/RuntimeException",
- "Error fetching EGL surface width/height");
- return;
- }
- __android_log_print(ANDROID_LOG_INFO, LOG_TAG,
- "New surface is %dx%d",
- _egl_surface_width, _egl_surface_height);
-
- CHECK_GL_ERROR();
-
// Turn off anything that looks like 3D ;)
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
@@ -664,7 +637,6 @@ void OSystem_Android::setupScummVMSurface() {
}
void OSystem_Android::destroyScummVMSurface() {
- _egl_surface = EGL_NO_SURFACE;
JNIEnv* env = JNU_GetEnv();
env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface);
// Can't use OpenGLES functions after this
@@ -745,8 +717,11 @@ void OSystem_Android::updateScreen() {
glPushMatrix();
- if (_shake_offset != 0) {
- // This is the only case where _game_texture doesn't
+ if (_shake_offset != 0 ||
+ (!_focus_rect.isEmpty() &&
+ !Common::Rect(_game_texture->width(),
+ _game_texture->height()).contains(_focus_rect))) {
+ // These are the only cases where _game_texture doesn't
// cover the entire screen.
glClearColorx(0, 0, 0, 1 << 16);
glClear(GL_COLOR_BUFFER_BIT);
@@ -759,16 +734,6 @@ void OSystem_Android::updateScreen() {
_game_texture->drawTexture(0, 0,
_egl_surface_width, _egl_surface_height);
} else {
- // Need to ensure any exposed out-of-bounds region doesn't go
- // all hall-of-mirrors. If _shake_offset != 0, we've already
- // done this above.
- const Common::Rect
- screen_bounds(_game_texture->width(), _game_texture->height());
- if (!screen_bounds.contains(_focus_rect) && _shake_offset != 0) {
- glClearColorx(0, 0, 0, 1 << 16);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-
glPushMatrix();
glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
xdiv(_egl_surface_height, _focus_rect.height()),
@@ -831,14 +796,11 @@ void OSystem_Android::updateScreen() {
CHECK_GL_ERROR();
- if (!eglSwapBuffers(_egl_display, _egl_surface)) {
- EGLint error = eglGetError();
- warning("eglSwapBuffers exited with error 0x%x", error);
- // Some errors mean we need to reinit GL
- if (error == EGL_CONTEXT_LOST) {
- destroyScummVMSurface();
- setupScummVMSurface();
- }
+ JNIEnv* env = JNU_GetEnv();
+ if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) {
+ // Context lost -> need to reinit GL
+ destroyScummVMSurface();
+ setupScummVMSurface();
}
}
@@ -1365,6 +1327,12 @@ static void ScummVM_enableZoning(JNIEnv* env, jobject self, jboolean enable) {
cpp_obj->enableZoning(enable);
}
+static void ScummVM_setSurfaceSize(JNIEnv* env, jobject self,
+ jint width, jint height) {
+ OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self);
+ cpp_obj->setSurfaceSize(width, height);
+}
+
const static JNINativeMethod gMethods[] = {
{ "create", "(Landroid/content/res/AssetManager;)V",
(void*)ScummVM_create },
@@ -1381,6 +1349,8 @@ const static JNINativeMethod gMethods[] = {
(void*)ScummVM_setConfManString },
{ "enableZoning", "(Z)V",
(void*)ScummVM_enableZoning },
+ { "setSurfaceSize", "(II)V",
+ (void*)ScummVM_setSurfaceSize },
};
JNIEXPORT jint JNICALL
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index 4ce8a85f30..d39aa363ef 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -12,7 +12,10 @@ import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
@@ -30,11 +33,11 @@ import java.util.concurrent.Semaphore;
public class ScummVM implements SurfaceHolder.Callback {
private final static String LOG_TAG = "ScummVM.java";
- private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo
+ private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo
public static class AudioSetupException extends Exception {}
private long nativeScummVM; // native code hangs itself here
- boolean scummVMRunning = false;
+ boolean scummVMRunning = false;
private native void create(AssetManager am);
@@ -54,49 +57,49 @@ public class ScummVM implements SurfaceHolder.Callback {
destroy();
}
- // Surface creation:
- // GUI thread: create surface, release lock
- // ScummVM thread: acquire lock (block), read surface
- //
- // Surface deletion:
- // GUI thread: post event, acquire lock (block), return
- // ScummVM thread: read event, free surface, release lock
- //
- // In other words, ScummVM thread does this:
- // acquire lock
- // setup surface
- // when SCREEN_CHANGED arrives:
- // destroy surface
- // release lock
- // back to acquire lock
- static final int configSpec[] = {
+ // Surface creation:
+ // GUI thread: create surface, release lock
+ // ScummVM thread: acquire lock (block), read surface
+ //
+ // Surface deletion:
+ // GUI thread: post event, acquire lock (block), return
+ // ScummVM thread: read event, free surface, release lock
+ //
+ // In other words, ScummVM thread does this:
+ // acquire lock
+ // setup surface
+ // when SCREEN_CHANGED arrives:
+ // destroy surface
+ // release lock
+ // back to acquire lock
+ static final int configSpec[] = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 5,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 0,
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_NONE,
- };
- EGL10 egl;
- EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY;
- EGLConfig eglConfig;
- EGLContext eglContext = EGL10.EGL_NO_CONTEXT;
- EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
- Semaphore surfaceLock = new Semaphore(0, true);
- SurfaceHolder nativeSurface;
-
- public void surfaceCreated(SurfaceHolder holder) {
+ };
+ EGL10 egl;
+ EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY;
+ EGLConfig eglConfig;
+ EGLContext eglContext = EGL10.EGL_NO_CONTEXT;
+ EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
+ Semaphore surfaceLock = new Semaphore(0, true);
+ SurfaceHolder nativeSurface;
+
+ public void surfaceCreated(SurfaceHolder holder) {
nativeSurface = holder;
surfaceLock.release();
- }
+ }
- public void surfaceChanged(SurfaceHolder holder, int format,
+ public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// Disabled while I debug GL problems
//pushEvent(new Event(Event.EVENT_SCREEN_CHANGED));
- }
+ }
- public void surfaceDestroyed(SurfaceHolder holder) {
+ public void surfaceDestroyed(SurfaceHolder holder) {
pushEvent(new Event(Event.EVENT_SCREEN_CHANGED));
try {
surfaceLock.acquire();
@@ -104,10 +107,10 @@ public class ScummVM implements SurfaceHolder.Callback {
Log.e(this.toString(),
"Interrupted while waiting for surface lock", e);
}
- }
+ }
- // Called by ScummVM thread (from initBackend)
- private void createScummVMGLContext() {
+ // Called by ScummVM thread (from initBackend)
+ private void createScummVMGLContext() {
egl = (EGL10)EGLContext.getEGL();
eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int[] version = new int[2];
@@ -126,10 +129,11 @@ public class ScummVM implements SurfaceHolder.Callback {
eglContext = egl.eglCreateContext(eglDisplay, eglConfig,
EGL10.EGL_NO_CONTEXT, null);
- }
+ }
- // Called by ScummVM thread
- protected void setupScummVMSurface() {
+ // Called by ScummVM thread
+ static private boolean _log_version = true;
+ protected void setupScummVMSurface() {
try {
surfaceLock.acquire();
} catch (InterruptedException e) {
@@ -140,10 +144,30 @@ public class ScummVM implements SurfaceHolder.Callback {
eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig,
nativeSurface, null);
egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
- }
- // Called by ScummVM thread
- protected void destroyScummVMSurface() {
+ GL10 gl = (GL10)eglContext.getGL();
+
+ if (_log_version) {
+ Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)",
+ egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION),
+ egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR),
+ gl.glGetString(GL10.GL_VERSION),
+ gl.glGetString(GL10.GL_RENDERER),
+ gl.glGetString(GL10.GL_VENDOR)));
+ _log_version = false; // only log this once
+ }
+
+ int[] value = new int[1];
+ egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, value);
+ int width = value[0];
+ egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, value);
+ int height = value[0];
+ Log.i(LOG_TAG, String.format("New surface is %dx%d", width, height));
+ setSurfaceSize(width, height);
+ }
+
+ // Called by ScummVM thread
+ protected void destroyScummVMSurface() {
if (eglSurface != null) {
egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
@@ -152,17 +176,28 @@ public class ScummVM implements SurfaceHolder.Callback {
}
surfaceLock.release();
- }
+ }
- public void setSurface(SurfaceHolder holder) {
+ public void setSurface(SurfaceHolder holder) {
holder.addCallback(this);
- }
+ }
+
+ final public boolean swapBuffers() {
+ if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {
+ int error = egl.eglGetError();
+ Log.w(LOG_TAG, String.format("eglSwapBuffers exited with error 0x%x", error));
+ if (error == EGL11.EGL_CONTEXT_LOST)
+ return false;
+ }
+ return true;
+ }
// Set scummvm config options
final public native static void loadConfigFile(String path);
final public native static void setConfMan(String key, int value);
final public native static void setConfMan(String key, String value);
final public native void enableZoning(boolean enable);
+ final public native void setSurfaceSize(int width, int height);
// Feed an event to ScummVM. Safe to call from other threads.
final public native void pushEvent(Event e);
@@ -180,10 +215,10 @@ public class ScummVM implements SurfaceHolder.Callback {
protected void showVirtualKeyboard(boolean enable) {}
protected String[] getSysArchives() { return new String[0]; }
protected String[] getPluginDirectories() { return new String[0]; }
- protected void initBackend() throws AudioSetupException {
+ protected void initBackend() throws AudioSetupException {
createScummVMGLContext();
initAudio();
- }
+ }
private static class AudioThread extends Thread {
final private int buf_size;
@@ -240,7 +275,7 @@ public class ScummVM implements SurfaceHolder.Callback {
break;
} else if (ret != len) {
Log.w(LOG_TAG, String.format(
- "Short audio write. Wrote %dB, not %dB",
+ "Short audio write. Wrote %dB, not %dB",
ret, buf.length));
// Buffer is full, so yield cpu for a while
Thread.sleep(100);
diff --git a/configure b/configure
index aaa8e1aee4..08613d2232 100755
--- a/configure
+++ b/configure
@@ -2515,7 +2515,7 @@ case $_backend in
# -lgcc is carefully placed here - we want to catch
# all toolchain symbols in *our* libraries rather
# than pick up anything unhygenic from the Android libs.
- LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -lstdc++ -llog -lGLESv1_CM -lEGL"
+ LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -lstdc++ -llog -lGLESv1_CM"
DEFINES="$DEFINES -D__ANDROID__ -DANDROID_BACKEND -DREDUCE_MEMORY_USAGE"
add_line_to_config_mk 'PLUGIN_LDFLAGS += $(LDFLAGS) -Wl,-shared,-Bsymbolic'