Merge pull request #45618 from RandomShaper/modernize_mt_3.2

Backport of all the multi-threading modernization (3.2)
This commit is contained in:
Hein-Pieter van Braam
2021-02-18 20:47:24 +01:00
committed by GitHub
191 changed files with 1688 additions and 4522 deletions

View File

@ -87,7 +87,7 @@ public:
v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
}
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
int res = env->PushLocalFrame(16);

View File

@ -48,7 +48,7 @@ int AudioDriverAndroid::mix_rate = 44100;
bool AudioDriverAndroid::quit = false;
jobject AudioDriverAndroid::audioBuffer = NULL;
void *AudioDriverAndroid::audioBufferPinned = NULL;
Mutex *AudioDriverAndroid::mutex = NULL;
Mutex AudioDriverAndroid::mutex;
int32_t *AudioDriverAndroid::audioBuffer32 = NULL;
const char *AudioDriverAndroid::get_name() const {
@ -58,7 +58,6 @@ const char *AudioDriverAndroid::get_name() const {
Error AudioDriverAndroid::init() {
mutex = Mutex::create();
/*
// TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
@ -75,7 +74,7 @@ Error AudioDriverAndroid::init() {
// __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
int mix_rate = GLOBAL_GET("audio/mix_rate");
int latency = GLOBAL_GET("audio/output_latency");
@ -102,7 +101,7 @@ void AudioDriverAndroid::start() {
void AudioDriverAndroid::setup(jobject p_io) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
io = p_io;
jclass c = env->GetObjectClass(io);
@ -133,7 +132,7 @@ void AudioDriverAndroid::thread_func(JNIEnv *env) {
int16_t *ptr = (int16_t *)audioBufferPinned;
int fc = audioBufferFrames;
if (!s_ad->active || mutex->try_lock() != OK) {
if (!s_ad->active || mutex.try_lock() != OK) {
for (int i = 0; i < fc; i++) {
ptr[i] = 0;
@ -143,7 +142,7 @@ void AudioDriverAndroid::thread_func(JNIEnv *env) {
s_ad->audio_server_process(fc / 2, audioBuffer32);
mutex->unlock();
mutex.unlock();
for (int i = 0; i < fc; i++) {
@ -167,19 +166,17 @@ AudioDriver::SpeakerMode AudioDriverAndroid::get_speaker_mode() const {
void AudioDriverAndroid::lock() {
if (mutex)
mutex->lock();
mutex.lock();
}
void AudioDriverAndroid::unlock() {
if (mutex)
mutex->unlock();
mutex.unlock();
}
void AudioDriverAndroid::finish() {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(io, _quit);
if (audioBuffer) {
@ -193,7 +190,7 @@ void AudioDriverAndroid::finish() {
void AudioDriverAndroid::set_pause(bool p_pause) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(io, _pause, p_pause);
}

View File

@ -37,7 +37,7 @@
class AudioDriverAndroid : public AudioDriver {
static Mutex *mutex;
static Mutex mutex;
static AudioDriverAndroid *s_ad;
static jobject io;
static jmethodID _init_audio;

View File

@ -44,8 +44,8 @@ void AudioDriverOpenSL::_buffer_callback(
if (pause) {
mix = false;
} else if (mutex) {
mix = mutex->try_lock() == OK;
} else {
mix = mutex.try_lock() == OK;
}
if (mix) {
@ -58,8 +58,8 @@ void AudioDriverOpenSL::_buffer_callback(
}
}
if (mutex && mix)
mutex->unlock();
if (mix)
mutex.unlock();
const int32_t *src_buff = mixdown_buffer;
@ -107,7 +107,6 @@ Error AudioDriverOpenSL::init() {
void AudioDriverOpenSL::start() {
mutex = Mutex::create();
active = false;
SLresult res;
@ -329,14 +328,14 @@ AudioDriver::SpeakerMode AudioDriverOpenSL::get_speaker_mode() const {
void AudioDriverOpenSL::lock() {
if (active && mutex)
mutex->lock();
if (active)
mutex.lock();
}
void AudioDriverOpenSL::unlock() {
if (active && mutex)
mutex->unlock();
if (active)
mutex.unlock();
}
void AudioDriverOpenSL::finish() {
@ -359,7 +358,6 @@ void AudioDriverOpenSL::set_pause(bool p_pause) {
AudioDriverOpenSL::AudioDriverOpenSL() {
s_ad = this;
mutex = Mutex::create(); //NULL;
pause = false;
active = false;
}

View File

@ -40,7 +40,7 @@
class AudioDriverOpenSL : public AudioDriver {
bool active;
Mutex *mutex;
Mutex mutex;
enum {

View File

@ -49,7 +49,7 @@ DirAccess *DirAccessJAndroid::create_fs() {
Error DirAccessJAndroid::list_dir_begin() {
list_dir_end();
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring js = env->NewStringUTF(current_dir.utf8().get_data());
int res = env->CallIntMethod(io, _dir_open, js);
@ -65,7 +65,7 @@ String DirAccessJAndroid::get_next() {
ERR_FAIL_COND_V(id == 0, "");
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring str = (jstring)env->CallObjectMethod(io, _dir_next, id);
if (!str)
return "";
@ -77,7 +77,7 @@ String DirAccessJAndroid::get_next() {
bool DirAccessJAndroid::current_is_dir() const {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallBooleanMethod(io, _dir_is_dir, id);
}
@ -92,7 +92,7 @@ void DirAccessJAndroid::list_dir_end() {
if (id == 0)
return;
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(io, _dir_close, id);
id = 0;
}
@ -109,7 +109,7 @@ String DirAccessJAndroid::get_drive(int p_drive) {
Error DirAccessJAndroid::change_dir(String p_dir) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
if (p_dir == "" || p_dir == "." || (p_dir == ".." && current_dir == ""))
return OK;
@ -166,7 +166,7 @@ bool DirAccessJAndroid::file_exists(String p_file) {
bool DirAccessJAndroid::dir_exists(String p_dir) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
String sd;
@ -225,7 +225,7 @@ size_t DirAccessJAndroid::get_space_left() {
void DirAccessJAndroid::setup(jobject p_io) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
io = p_io;
jclass c = env->GetObjectClass(io);

View File

@ -37,6 +37,7 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/safe_refcount.h"
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "editor/editor_export.h"
@ -280,42 +281,42 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<PluginConfigAndroid> plugins;
String last_plugin_names;
uint64_t last_custom_build_time = 0;
volatile bool plugins_changed;
Mutex *plugins_lock;
SafeFlag plugins_changed;
Mutex plugins_lock;
Vector<Device> devices;
volatile bool devices_changed;
Mutex *device_lock;
Thread *check_for_changes_thread;
volatile bool quit_request;
SafeFlag devices_changed;
Mutex device_lock;
Thread check_for_changes_thread;
SafeFlag quit_request;
static void _check_for_changes_poll_thread(void *ud) {
EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
while (!ea->quit_request) {
while (!ea->quit_request.is_set()) {
// Check for plugins updates
{
// Nothing to do if we already know the plugins have changed.
if (!ea->plugins_changed) {
if (!ea->plugins_changed.is_set()) {
Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
ea->plugins_lock->lock();
ea->plugins_lock.lock();
if (ea->plugins.size() != loaded_plugins.size()) {
ea->plugins_changed = true;
ea->plugins_changed.set();
} else {
for (int i = 0; i < ea->plugins.size(); i++) {
if (ea->plugins[i].name != loaded_plugins[i].name) {
ea->plugins_changed = true;
ea->plugins_changed.set();
break;
}
}
}
if (ea->plugins_changed) {
if (ea->plugins_changed.is_set()) {
ea->plugins = loaded_plugins;
}
ea->plugins_lock->unlock();
ea->plugins_lock.unlock();
}
}
@ -341,7 +342,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
ldevices.push_back(d);
}
ea->device_lock->lock();
ea->device_lock.lock();
bool different = false;
@ -428,10 +429,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
ea->devices = ndevices;
ea->devices_changed = true;
ea->devices_changed.set();
}
ea->device_lock->unlock();
ea->device_lock.unlock();
}
uint64_t sleep = OS::get_singleton()->get_power_state() == OS::POWERSTATE_ON_BATTERY ? 1000 : 100;
@ -439,7 +440,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
uint64_t time = OS::get_singleton()->get_ticks_usec();
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
OS::get_singleton()->delay_usec(1000 * sleep);
if (ea->quit_request)
if (ea->quit_request.is_set())
break;
}
}
@ -1704,7 +1705,7 @@ public:
print_verbose("Found Android plugin " + plugins_configs[i].name);
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false));
}
plugins_changed = false;
plugins_changed.clear();
Vector<String> abis = get_abis();
for (int i = 0; i < abis.size(); ++i) {
@ -1775,29 +1776,29 @@ public:
}
virtual bool should_update_export_options() {
bool export_options_changed = plugins_changed;
bool export_options_changed = plugins_changed.is_set();
if (export_options_changed) {
// don't clear unless we're reporting true, to avoid race
plugins_changed = false;
plugins_changed.clear();
}
return export_options_changed;
}
virtual bool poll_export() {
bool dc = devices_changed;
bool dc = devices_changed.is_set();
if (dc) {
// don't clear unless we're reporting true, to avoid race
devices_changed = false;
devices_changed.clear();
}
return dc;
}
virtual int get_options_count() const {
device_lock->lock();
device_lock.lock();
int dc = devices.size();
device_lock->unlock();
device_lock.unlock();
return dc;
}
@ -1810,16 +1811,16 @@ public:
virtual String get_option_label(int p_index) const {
ERR_FAIL_INDEX_V(p_index, devices.size(), "");
device_lock->lock();
device_lock.lock();
String s = devices[p_index].name;
device_lock->unlock();
device_lock.unlock();
return s;
}
virtual String get_option_tooltip(int p_index) const {
ERR_FAIL_INDEX_V(p_index, devices.size(), "");
device_lock->lock();
device_lock.lock();
String s = devices[p_index].description;
if (devices.size() == 1) {
// Tooltip will be:
@ -1827,7 +1828,7 @@ public:
// Description
s = devices[p_index].name + "\n\n" + s;
}
device_lock->unlock();
device_lock.unlock();
return s;
}
@ -1842,7 +1843,7 @@ public:
return ERR_UNCONFIGURED;
}
device_lock->lock();
device_lock.lock();
EditorProgress ep("run", "Running on " + devices[p_device].name, 3);
@ -1850,7 +1851,7 @@ public:
// Export_temp APK.
if (ep.step("Exporting APK...", 0)) {
device_lock->unlock();
device_lock.unlock();
return ERR_SKIP;
}
@ -1865,7 +1866,7 @@ public:
#define CLEANUP_AND_RETURN(m_err) \
{ \
DirAccess::remove_file_or_error(tmp_export_path); \
device_lock->unlock(); \
device_lock.unlock(); \
return m_err; \
}
@ -3305,21 +3306,14 @@ public:
run_icon.instance();
run_icon->create_from_image(img);
device_lock = Mutex::create();
devices_changed = true;
plugins_lock = Mutex::create();
plugins_changed = true;
quit_request = false;
check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this);
devices_changed.set();
plugins_changed.set();
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
}
~EditorExportPlatformAndroid() {
quit_request = true;
Thread::wait_to_finish(check_for_changes_thread);
memdelete(plugins_lock);
memdelete(device_lock);
memdelete(check_for_changes_thread);
quit_request.set();
check_for_changes_thread.wait_to_finish();
}
};

View File

@ -38,7 +38,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
if (!M)
return false;
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
MethodInfo *method = NULL;
for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) {
@ -1048,7 +1048,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
if (class_cache.has(p_class))
return class_cache[p_class];
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jclass bclass = env->FindClass(p_class.utf8().get_data());
ERR_FAIL_COND_V(!bclass, Ref<JavaClass>());
@ -1242,7 +1242,7 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
singleton = this;
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jclass activityClass = env->FindClass("android/app/Activity");
jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");

View File

@ -76,7 +76,7 @@ jobject GodotIOJavaWrapper::get_instance() {
Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
if (_open_URI) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
} else {
@ -86,7 +86,7 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
String GodotIOJavaWrapper::get_user_data_dir() {
if (_get_data_dir) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
return jstring_to_string(s, env);
} else {
@ -96,7 +96,7 @@ String GodotIOJavaWrapper::get_user_data_dir() {
String GodotIOJavaWrapper::get_locale() {
if (_get_locale) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale);
return jstring_to_string(s, env);
} else {
@ -106,7 +106,7 @@ String GodotIOJavaWrapper::get_locale() {
String GodotIOJavaWrapper::get_model() {
if (_get_model) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model);
return jstring_to_string(s, env);
} else {
@ -116,7 +116,7 @@ String GodotIOJavaWrapper::get_model() {
int GodotIOJavaWrapper::get_screen_dpi() {
if (_get_screen_DPI) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallIntMethod(godot_io_instance, _get_screen_DPI);
} else {
return 160;
@ -125,7 +125,7 @@ int GodotIOJavaWrapper::get_screen_dpi() {
void GodotIOJavaWrapper::get_window_safe_area(int (&p_rect_xywh)[4]) {
if (_get_window_safe_area) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _get_window_safe_area);
ERR_FAIL_COND(env->GetArrayLength(returnArray) != 4);
jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE);
@ -138,7 +138,7 @@ void GodotIOJavaWrapper::get_window_safe_area(int (&p_rect_xywh)[4]) {
String GodotIOJavaWrapper::get_unique_id() {
if (_get_unique_id) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_id);
return jstring_to_string(s, env);
} else {
@ -152,7 +152,7 @@ bool GodotIOJavaWrapper::has_vk() {
void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
}
@ -160,21 +160,21 @@ void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int
void GodotIOJavaWrapper::hide_vk() {
if (_hide_keyboard) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_io_instance, _hide_keyboard);
}
}
void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
if (_set_screen_orientation) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
}
}
int GodotIOJavaWrapper::get_screen_orientation() const {
if (_get_screen_orientation) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallIntMethod(godot_io_instance, _get_screen_orientation);
} else {
return 0;
@ -183,7 +183,7 @@ int GodotIOJavaWrapper::get_screen_orientation() const {
String GodotIOJavaWrapper::get_system_dir(int p_dir) {
if (_get_system_dir) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
return jstring_to_string(s, env);
} else {
@ -197,7 +197,7 @@ void GodotIOJavaWrapper::play_video(const String &p_path) {
bool GodotIOJavaWrapper::is_video_playing() {
if (_is_video_playing) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallBooleanMethod(godot_io_instance, _is_video_playing);
} else {
return false;
@ -206,26 +206,26 @@ bool GodotIOJavaWrapper::is_video_playing() {
void GodotIOJavaWrapper::pause_video() {
if (_pause_video) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_io_instance, _pause_video);
}
}
void GodotIOJavaWrapper::stop_video() {
if (_stop_video) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_io_instance, _stop_video);
}
}
// volatile because it can be changed from non-main thread and we need to
// SafeNumeric because it can be changed from non-main thread and we need to
// ensure the change is immediately visible to other threads.
static volatile int virtual_keyboard_height;
static SafeNumeric<int> virtual_keyboard_height;
int GodotIOJavaWrapper::get_vk_height() {
return virtual_keyboard_height;
return virtual_keyboard_height.get();
}
void GodotIOJavaWrapper::set_vk_height(int p_height) {
virtual_keyboard_height = p_height;
virtual_keyboard_height.set(p_height);
}

View File

@ -84,7 +84,7 @@ static void _initialize_java_modules() {
// TODO create wrapper for class loader
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jclass classLoader = env->FindClass("java/lang/ClassLoader");
jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
@ -132,7 +132,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
godot_java = new GodotJavaWrapper(env, activity, godot_instance);
godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env));
ThreadAndroid::make_default(jvm);
init_thread_jandroid(jvm, env);
jobject amgr = env->NewGlobalRef(p_asset_manager);
@ -164,7 +164,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) {
ThreadAndroid::setup_thread();
setup_android_thread();
const char **cmdline = NULL;
jstring *j_cmdline = NULL;
@ -422,7 +422,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env,
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz) {
ThreadAndroid::setup_thread();
setup_android_thread();
AudioDriverAndroid::thread_func(env);
}

View File

@ -91,7 +91,7 @@ jobject GodotJavaWrapper::get_activity() {
jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) {
if (godot_class) {
if (p_env == NULL)
p_env = ThreadAndroid::get_env();
p_env = get_jni_env();
jfieldID fid = p_env->GetStaticFieldID(godot_class, p_name, p_class);
return p_env->GetStaticObjectField(godot_class, fid);
@ -102,7 +102,7 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl
jobject GodotJavaWrapper::get_class_loader() {
if (_get_class_loader) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallObjectMethod(activity, _get_class_loader);
} else {
return NULL;
@ -119,7 +119,7 @@ void GodotJavaWrapper::gfx_init(bool gl2) {
void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
if (_on_video_init)
if (p_env == NULL)
p_env = ThreadAndroid::get_env();
p_env = get_jni_env();
p_env->CallVoidMethod(godot_instance, _on_video_init);
}
@ -127,7 +127,7 @@ void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
if (_on_godot_main_loop_started) {
if (p_env == NULL) {
p_env = ThreadAndroid::get_env();
p_env = get_jni_env();
}
}
p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
@ -136,7 +136,7 @@ void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
void GodotJavaWrapper::restart(JNIEnv *p_env) {
if (_restart)
if (p_env == NULL)
p_env = ThreadAndroid::get_env();
p_env = get_jni_env();
p_env->CallVoidMethod(godot_instance, _restart);
}
@ -144,21 +144,21 @@ void GodotJavaWrapper::restart(JNIEnv *p_env) {
void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
if (_finish)
if (p_env == NULL)
p_env = ThreadAndroid::get_env();
p_env = get_jni_env();
p_env->CallVoidMethod(godot_instance, _finish);
}
void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
if (_set_keep_screen_on) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled);
}
}
void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
if (_alert) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
@ -166,7 +166,7 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
}
int GodotJavaWrapper::get_gles_version_code() {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
if (_get_GLES_version_code) {
return env->CallIntMethod(godot_instance, _get_GLES_version_code);
}
@ -180,7 +180,7 @@ bool GodotJavaWrapper::has_get_clipboard() {
String GodotJavaWrapper::get_clipboard() {
if (_get_clipboard) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard);
return jstring_to_string(s, env);
} else {
@ -190,7 +190,7 @@ String GodotJavaWrapper::get_clipboard() {
String GodotJavaWrapper::get_input_fallback_mapping() {
if (_get_input_fallback_mapping) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring fallback_mapping = (jstring)env->CallObjectMethod(godot_instance, _get_input_fallback_mapping);
return jstring_to_string(fallback_mapping, env);
} else {
@ -204,7 +204,7 @@ bool GodotJavaWrapper::has_set_clipboard() {
void GodotJavaWrapper::set_clipboard(const String &p_text) {
if (_set_clipboard) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
}
@ -212,7 +212,7 @@ void GodotJavaWrapper::set_clipboard(const String &p_text) {
bool GodotJavaWrapper::request_permission(const String &p_name) {
if (_request_permission) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
} else {
@ -222,7 +222,7 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
bool GodotJavaWrapper::request_permissions() {
if (_request_permissions) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallBooleanMethod(godot_instance, _request_permissions);
} else {
return false;
@ -232,7 +232,7 @@ bool GodotJavaWrapper::request_permissions() {
Vector<String> GodotJavaWrapper::get_granted_permissions() const {
Vector<String> permissions_list;
if (_get_granted_permissions) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions);
jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object);
@ -250,14 +250,14 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
void GodotJavaWrapper::init_input_devices() {
if (_init_input_devices) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_instance, _init_input_devices);
}
}
jobject GodotJavaWrapper::get_surface() {
if (_get_surface) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallObjectMethod(godot_instance, _get_surface);
} else {
return NULL;
@ -266,7 +266,7 @@ jobject GodotJavaWrapper::get_surface() {
bool GodotJavaWrapper::is_activity_resumed() {
if (_is_activity_resumed) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
return env->CallBooleanMethod(godot_instance, _is_activity_resumed);
} else {
return false;
@ -275,7 +275,7 @@ bool GodotJavaWrapper::is_activity_resumed() {
void GodotJavaWrapper::vibrate(int p_duration_ms) {
if (_vibrate) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms);
}
}

View File

@ -39,7 +39,7 @@ jmethodID NetSocketAndroid::_multicast_lock_release = 0;
void NetSocketAndroid::setup(jobject p_net_utils) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
net_utils = env->NewGlobalRef(p_net_utils);
@ -52,14 +52,14 @@ void NetSocketAndroid::setup(jobject p_net_utils) {
void NetSocketAndroid::multicast_lock_acquire() {
if (_multicast_lock_acquire) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(net_utils, _multicast_lock_acquire);
}
}
void NetSocketAndroid::multicast_lock_release() {
if (_multicast_lock_release) {
JNIEnv *env = ThreadAndroid::get_env();
JNIEnv *env = get_jni_env();
env->CallVoidMethod(net_utils, _multicast_lock_release);
}
}

View File

@ -37,14 +37,14 @@
/**
* Converts JNI jstring to Godot String.
* @param source Source JNI string. If null an empty string is returned.
* @param env JNI environment instance. If null obtained by ThreadAndroid::get_env().
* @param env JNI environment instance. If null obtained by get_jni_env().
* @return Godot string instance.
*/
static inline String jstring_to_string(jstring source, JNIEnv *env = NULL) {
String result;
if (source) {
if (!env) {
env = ThreadAndroid::get_env();
env = get_jni_env();
}
const char *const source_utf8 = env->GetStringUTFChars(source, NULL);
if (source_utf8) {

View File

@ -30,127 +30,29 @@
#include "thread_jandroid.h"
#include "core/os/memory.h"
#include "core/safe_refcount.h"
#include "core/script_language.h"
#include "core/os/thread.h"
static void _thread_id_key_destr_callback(void *p_value) {
memdelete(static_cast<Thread::ID *>(p_value));
static JavaVM *java_vm = nullptr;
static thread_local JNIEnv *env = nullptr;
static void init_thread() {
java_vm->AttachCurrentThread(&env, nullptr);
}
static pthread_key_t _create_thread_id_key() {
pthread_key_t key;
pthread_key_create(&key, &_thread_id_key_destr_callback);
return key;
static void term_thread() {
java_vm->DetachCurrentThread();
}
pthread_key_t ThreadAndroid::thread_id_key = _create_thread_id_key();
Thread::ID ThreadAndroid::next_thread_id = 0;
Thread::ID ThreadAndroid::get_id() const {
return id;
void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
java_vm = p_jvm;
env = p_env;
Thread::_set_platform_funcs(nullptr, nullptr, &init_thread, &term_thread);
}
Thread *ThreadAndroid::create_thread_jandroid() {
return memnew(ThreadAndroid);
void setup_android_thread() {
init_thread();
}
void *ThreadAndroid::thread_callback(void *userdata) {
ThreadAndroid *t = reinterpret_cast<ThreadAndroid *>(userdata);
setup_thread();
ScriptServer::thread_enter(); //scripts may need to attach a stack
t->id = atomic_increment(&next_thread_id);
pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id)));
t->callback(t->user);
ScriptServer::thread_exit();
return NULL;
}
Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
ThreadAndroid *tr = memnew(ThreadAndroid);
tr->callback = p_callback;
tr->user = p_user;
pthread_attr_init(&tr->pthread_attr);
pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
return tr;
}
Thread::ID ThreadAndroid::get_thread_id_func_jandroid() {
void *value = pthread_getspecific(thread_id_key);
if (value)
return *static_cast<ID *>(value);
ID new_id = atomic_increment(&next_thread_id);
pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id)));
return new_id;
}
void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) {
ThreadAndroid *tp = static_cast<ThreadAndroid *>(p_thread);
ERR_FAIL_COND(!tp);
ERR_FAIL_COND(tp->pthread == 0);
pthread_join(tp->pthread, NULL);
tp->pthread = 0;
}
void ThreadAndroid::_thread_destroyed(void *value) {
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
JNIEnv *env = (JNIEnv *)value;
if (env != NULL) {
java_vm->DetachCurrentThread();
pthread_setspecific(jvm_key, NULL);
}
}
pthread_key_t ThreadAndroid::jvm_key;
JavaVM *ThreadAndroid::java_vm = NULL;
void ThreadAndroid::setup_thread() {
if (pthread_getspecific(jvm_key))
return; //already setup
JNIEnv *env;
java_vm->AttachCurrentThread(&env, NULL);
pthread_setspecific(jvm_key, (void *)env);
}
void ThreadAndroid::make_default(JavaVM *p_java_vm) {
java_vm = p_java_vm;
create_func = create_func_jandroid;
get_thread_id_func = get_thread_id_func_jandroid;
wait_to_finish_func = wait_to_finish_func_jandroid;
pthread_key_create(&jvm_key, _thread_destroyed);
setup_thread();
}
JNIEnv *ThreadAndroid::get_env() {
if (!pthread_getspecific(jvm_key)) {
setup_thread();
}
JNIEnv *env = NULL;
java_vm->AttachCurrentThread(&env, NULL);
JNIEnv *get_jni_env() {
return env;
}
ThreadAndroid::ThreadAndroid() {
pthread = 0;
}
ThreadAndroid::~ThreadAndroid() {
}

View File

@ -28,47 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef THREAD_POSIX_H
#define THREAD_POSIX_H
#ifndef THREAD_JANDROID_H
#define THREAD_JANDROID_H
#include "core/os/thread.h"
#include <jni.h>
#include <pthread.h>
#include <sys/types.h>
class ThreadAndroid : public Thread {
void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env);
static pthread_key_t thread_id_key;
static ID next_thread_id;
pthread_t pthread;
pthread_attr_t pthread_attr;
ThreadCreateCallback callback;
void *user;
ID id;
static Thread *create_thread_jandroid();
static void *thread_callback(void *userdata);
static Thread *create_func_jandroid(ThreadCreateCallback p_callback, void *, const Settings &);
static ID get_thread_id_func_jandroid();
static void wait_to_finish_func_jandroid(Thread *p_thread);
static void _thread_destroyed(void *value);
ThreadAndroid();
static pthread_key_t jvm_key;
static JavaVM *java_vm;
public:
virtual ID get_id() const;
static void make_default(JavaVM *p_java_vm);
static void setup_thread();
static JNIEnv *get_env();
~ThreadAndroid();
};
void setup_android_thread();
JNIEnv *get_jni_env();
#endif