Merge pull request #26672 from RandomShaper/fix-22955-android-context-loss
Restart game on GL context loss on Android
This commit is contained in:
commit
1100d6a8f2
|
@ -36,4 +36,9 @@ $$ADD_APPLICATION_CHUNKS$$
|
|||
|
||||
</application>
|
||||
|
||||
<instrumentation android:icon="@drawable/icon"
|
||||
android:label="@string/godot_project_name_string"
|
||||
android:name="org.godotengine.godot.GodotInstrumentation"
|
||||
android:targetPackage="com.godot.game" />
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -38,6 +38,7 @@ import android.app.AlertDialog;
|
|||
import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
@ -318,6 +319,23 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
|
|||
});
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
// HACK:
|
||||
//
|
||||
// Currently it's very hard to properly deinitialize Godot on Android to restart the game
|
||||
// from scratch. Therefore, we need to kill the whole app process and relaunch it.
|
||||
//
|
||||
// Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
|
||||
// releasing and reloading native libs or resetting their state somehow and clearing statics).
|
||||
//
|
||||
// Using instrumentation is a way of making the whole app process restart, because Android
|
||||
// will kill any process of the same package which was already running.
|
||||
//
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable("intent", mCurrentIntent);
|
||||
startInstrumentation(new ComponentName(Godot.this, GodotInstrumentation.class), null, args);
|
||||
}
|
||||
|
||||
public void alert(final String message, final String title) {
|
||||
final Activity activity = this;
|
||||
runOnUiThread(new Runnable() {
|
||||
|
@ -415,7 +433,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
|
|||
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
|
||||
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
|
||||
|
||||
GodotLib.initialize(this, io.needsReloadHooks(), getAssets(), use_apk_expansion);
|
||||
GodotLib.initialize(this, getAssets(), use_apk_expansion);
|
||||
|
||||
result_callback = null;
|
||||
|
||||
|
@ -921,10 +939,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
|
|||
// Audio
|
||||
|
||||
/**
|
||||
* The download state should trigger changes in the UI --- it may be useful
|
||||
* to show the state as being indeterminate at times. This sample can be
|
||||
* considered a guideline.
|
||||
*/
|
||||
* The download state should trigger changes in the UI --- it may be useful
|
||||
* to show the state as being indeterminate at times. This sample can be
|
||||
* considered a guideline.
|
||||
*/
|
||||
@Override
|
||||
public void onDownloadStateChanged(int newState) {
|
||||
setState(newState);
|
||||
|
|
|
@ -500,11 +500,6 @@ public class GodotIO {
|
|||
return (int)(metrics.density * 160f);
|
||||
}
|
||||
|
||||
public boolean needsReloadHooks() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void showKeyboard(String p_existing_text) {
|
||||
if (edit != null)
|
||||
edit.showKeyboard(p_existing_text);
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*************************************************************************/
|
||||
/* GodotInstrumentation.java */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
package org.godotengine.godot;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class GodotInstrumentation extends Instrumentation {
|
||||
private Intent intent;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle arguments) {
|
||||
intent = arguments.getParcelable("intent");
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
startActivitySync(intent);
|
||||
}
|
||||
}
|
|
@ -45,9 +45,9 @@ public class GodotLib {
|
|||
* @param height the current view height
|
||||
*/
|
||||
|
||||
public static native void initialize(Godot p_instance, boolean need_reload_hook, Object p_asset_manager, boolean use_apk_expansion);
|
||||
public static native void initialize(Godot p_instance, Object p_asset_manager, boolean use_apk_expansion);
|
||||
public static native void setup(String[] p_cmdline);
|
||||
public static native void resize(int width, int height, boolean reload);
|
||||
public static native void resize(int width, int height);
|
||||
public static native void newcontext(boolean p_32_bits);
|
||||
public static native void back();
|
||||
public static native void step();
|
||||
|
|
|
@ -79,7 +79,6 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
|
|||
private Context ctx;
|
||||
|
||||
private GodotIO io;
|
||||
private static boolean firsttime = true;
|
||||
private static boolean use_gl3 = false;
|
||||
private static boolean use_32 = false;
|
||||
private static boolean use_debug_opengl = false;
|
||||
|
@ -97,10 +96,8 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
|
|||
|
||||
activity = p_activity;
|
||||
|
||||
if (!p_io.needsReloadHooks()) {
|
||||
//will only work on SDK 11+!!
|
||||
setPreserveEGLContextOnPause(true);
|
||||
}
|
||||
setPreserveEGLContextOnPause(true);
|
||||
|
||||
mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext());
|
||||
mInputManager.registerInputDeviceListener(this, null);
|
||||
init(false, 16, 0);
|
||||
|
@ -718,8 +715,7 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {
|
|||
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
|
||||
GodotLib.resize(width, height, !firsttime);
|
||||
firsttime = false;
|
||||
GodotLib.resize(width, height);
|
||||
for (int i = 0; i < Godot.singleton_count; i++) {
|
||||
Godot.singletons[i].onGLSurfaceChanged(gl, width, height);
|
||||
}
|
||||
|
|
|
@ -599,6 +599,7 @@ static jobject godot_io;
|
|||
typedef void (*GFXInitFunc)(void *ud, bool gl2);
|
||||
|
||||
static jmethodID _on_video_init = 0;
|
||||
static jmethodID _restart = 0;
|
||||
static jobject _godot_instance;
|
||||
|
||||
static jmethodID _openURI = 0;
|
||||
|
@ -757,7 +758,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHei
|
|||
virtual_keyboard_height = p_height;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) {
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion) {
|
||||
|
||||
initialized = true;
|
||||
|
||||
|
@ -783,6 +784,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
|
|||
godot_io = gob;
|
||||
|
||||
_on_video_init = env->GetMethodID(cls, "onVideoInit", "()V");
|
||||
_restart = env->GetMethodID(cls, "restart", "()V");
|
||||
_setKeepScreenOn = env->GetMethodID(cls, "setKeepScreenOn", "(Z)V");
|
||||
_alertDialog = env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
_getGLESVersionCode = env->GetMethodID(cls, "getGLESVersionCode", "()I");
|
||||
|
@ -821,7 +823,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
|
|||
}
|
||||
|
||||
os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _get_gles_version_code, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, _set_clipboard, _get_clipboard, p_use_apk_expansion);
|
||||
os_android->set_need_reload_hooks(p_need_reload_hook);
|
||||
|
||||
char wd[500];
|
||||
getcwd(wd, 500);
|
||||
|
@ -932,7 +933,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
|
|||
_initialize_java_modules();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload) {
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height) {
|
||||
|
||||
if (os_android)
|
||||
os_android->set_display_size(Size2(width, height));
|
||||
|
@ -941,12 +942,15 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
|
|||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) {
|
||||
|
||||
if (os_android) {
|
||||
os_android->set_context_is_16_bits(!p_32_bits);
|
||||
}
|
||||
|
||||
if (os_android && step > 0) {
|
||||
|
||||
os_android->reload_gfx();
|
||||
if (step == 0) {
|
||||
// During startup
|
||||
os_android->set_context_is_16_bits(!p_32_bits);
|
||||
} else {
|
||||
// GL context recreated because it was lost; restart app to let it reload everything
|
||||
os_android->main_loop_end();
|
||||
env->CallVoidMethod(_godot_instance, _restart);
|
||||
step = -1; // Ensure no further steps are attempted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -958,6 +962,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, job
|
|||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
|
||||
if (step == -1)
|
||||
return;
|
||||
|
||||
if (step == 0) {
|
||||
|
||||
// Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id,
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
#include <jni.h>
|
||||
|
||||
extern "C" {
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height, jboolean reload);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj);
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj);
|
||||
|
|
|
@ -548,14 +548,6 @@ void OS_Android::set_display_size(Size2 p_size) {
|
|||
default_videomode.height = p_size.y;
|
||||
}
|
||||
|
||||
void OS_Android::reload_gfx() {
|
||||
|
||||
if (gfx_init_func)
|
||||
gfx_init_func(gfx_init_ud, use_gl2);
|
||||
//if (rasterizer)
|
||||
// rasterizer->reload_vram();
|
||||
}
|
||||
|
||||
Error OS_Android::shell_open(String p_uri) {
|
||||
|
||||
if (open_uri_func)
|
||||
|
@ -607,11 +599,6 @@ int OS_Android::get_screen_dpi(int p_screen) const {
|
|||
return 160;
|
||||
}
|
||||
|
||||
void OS_Android::set_need_reload_hooks(bool p_needs_them) {
|
||||
|
||||
use_reload_hooks = p_needs_them;
|
||||
}
|
||||
|
||||
String OS_Android::get_user_data_dir() const {
|
||||
|
||||
if (data_dir_cache != String())
|
||||
|
@ -765,7 +752,6 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
|
|||
set_screen_orientation_func = p_screen_orient;
|
||||
set_keep_screen_on_func = p_set_keep_screen_on_func;
|
||||
alert_func = p_alert_func;
|
||||
use_reload_hooks = false;
|
||||
|
||||
Vector<Logger *> loggers;
|
||||
loggers.push_back(memnew(AndroidLogger));
|
||||
|
|
|
@ -94,7 +94,6 @@ private:
|
|||
void *gfx_init_ud;
|
||||
|
||||
bool use_gl2;
|
||||
bool use_reload_hooks;
|
||||
bool use_apk_expansion;
|
||||
|
||||
bool use_16bits_fbo;
|
||||
|
@ -203,10 +202,8 @@ public:
|
|||
void set_opengl_extensions(const char *p_gl_extensions);
|
||||
void set_display_size(Size2 p_size);
|
||||
|
||||
void reload_gfx();
|
||||
void set_context_is_16_bits(bool p_is_16);
|
||||
|
||||
void set_need_reload_hooks(bool p_needs_them);
|
||||
virtual void set_screen_orientation(ScreenOrientation p_orientation);
|
||||
|
||||
virtual Error shell_open(String p_uri);
|
||||
|
|
Loading…
Reference in New Issue