Skip to content

Commit d8eea1e

Browse files
committed
Support multi-threaded rendering with OpenGL on Android
1 parent 1659b4b commit d8eea1e

File tree

12 files changed

+95
-15
lines changed

12 files changed

+95
-15
lines changed

platform/android/display_server_android.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -485,24 +485,16 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type,
485485
}
486486
#ifdef GLES3_ENABLED
487487
case DISPLAY_HANDLE: {
488-
if (rendering_driver == "opengl3") {
489-
return reinterpret_cast<int64_t>(eglGetCurrentDisplay());
490-
}
491-
return 0;
488+
return reinterpret_cast<int64_t>(egl_display);
492489
}
493490
case OPENGL_CONTEXT: {
494-
if (rendering_driver == "opengl3") {
495-
return reinterpret_cast<int64_t>(eglGetCurrentContext());
496-
}
497-
return 0;
491+
return reinterpret_cast<int64_t>(egl_context);
498492
}
499493
case EGL_DISPLAY: {
500-
// @todo Find a way to get this from the Java side.
501-
return 0;
494+
return reinterpret_cast<int64_t>(egl_display);
502495
}
503496
case EGL_CONFIG: {
504-
// @todo Find a way to get this from the Java side.
505-
return 0;
497+
return reinterpret_cast<int64_t>(egl_config);
506498
}
507499
#endif
508500
default: {
@@ -715,6 +707,15 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
715707
}
716708
}
717709

710+
void DisplayServerAndroid::update_egl_resources(void *p_display, void *p_surface, void *p_context, void *p_config) {
711+
#ifdef GLES3_ENABLED
712+
egl_display = p_display;
713+
egl_surface = p_surface;
714+
egl_context = p_context;
715+
egl_config = p_config;
716+
#endif
717+
}
718+
718719
DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
719720
rendering_driver = p_rendering_driver;
720721

@@ -796,6 +797,11 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
796797
#if defined(GLES3_ENABLED)
797798
if (rendering_driver == "opengl3") {
798799
RasterizerGLES3::make_current(false);
800+
801+
if (OS::get_singleton()->is_separate_thread_rendering_enabled()) {
802+
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
803+
godot_java->set_separate_render_thread_enabled(true);
804+
}
799805
}
800806
#endif
801807

@@ -962,6 +968,7 @@ void DisplayServerAndroid::release_rendering_thread() {
962968
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
963969
ERR_FAIL_NULL(godot_java);
964970
godot_java->release_current_gl_window(egl_current_window_id);
971+
egl_current_window_id = INVALID_WINDOW_ID;
965972
}
966973

967974
void DisplayServerAndroid::swap_buffers() {

platform/android/display_server_android.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ class DisplayServerAndroid : public DisplayServer {
7979
RenderingContextDriver *rendering_context = nullptr;
8080
RenderingDevice *rendering_device = nullptr;
8181
#endif
82+
83+
#ifdef GLES3_ENABLED
84+
void *egl_display = nullptr;
85+
void *egl_surface = nullptr;
86+
void *egl_context = nullptr;
87+
void *egl_config = nullptr;
88+
#endif
89+
8290
NativeMenu *native_menu = nullptr;
8391

8492
ObjectID window_attached_instance_id;
@@ -245,6 +253,7 @@ class DisplayServerAndroid : public DisplayServer {
245253

246254
void reset_window();
247255
void notify_surface_changed(int p_width, int p_height);
256+
void update_egl_resources(void *p_display, void *p_surface, void *p_context, void *p_config);
248257

249258
virtual Point2i mouse_get_position() const override;
250259
virtual BitField<MouseButtonMask> mouse_get_button_state() const override;

platform/android/java/lib/src/org/godotengine/godot/Godot.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,11 @@ class Godot private constructor(val context: Context) {
13821382
renderView?.view?.pointerIcon = pointerIcon
13831383
}
13841384

1385+
@Keep
1386+
private fun setSeparateRenderThreadEnabled(enabled: Boolean) {
1387+
renderer.renderThread.setSeparateRenderThreadEnabled(enabled)
1388+
}
1389+
13851390
@Keep
13861391
private fun makeGLWindowCurrent(windowId: Int): Boolean {
13871392
return renderer.renderThread.makeEglCurrent(windowId)

platform/android/java/lib/src/org/godotengine/godot/GodotLib.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public static native boolean initialize(
8989
*/
9090
public static native void newcontext(Surface p_surface);
9191

92+
/**
93+
* Invoked on the render thread when any of the EGL resources may have changed.
94+
*/
95+
public static native void updateEglResources(long display, long surface, long context, long config);
96+
9297
/**
9398
* Forward {@link Activity#onBackPressed()} event.
9499
*/

platform/android/java/lib/src/org/godotengine/godot/render/GLSurfaceView.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ public void start() {
815815
*
816816
* @return true if the surface was created successfully.
817817
*/
818-
public boolean createSurface() {
818+
public boolean createSurface(boolean requireMakeCurrent) {
819819
if (LOG_EGL) {
820820
Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
821821
}
@@ -854,7 +854,7 @@ public boolean createSurface() {
854854
return false;
855855
}
856856

857-
if (!makeEglCurrent()) {
857+
if (!makeEglCurrent() && requireMakeCurrent) {
858858
return false;
859859
}
860860

@@ -1261,11 +1261,13 @@ private void guardedRun() throws InterruptedException {
12611261
}
12621262

12631263
if (mRegisteredGLSurface != null) {
1264+
boolean eglResourcesChanged = false;
1265+
12641266
if (mRegisteredGLSurface.mFrameParams.createEglSurface) {
12651267
if (LOG_SURFACE) {
12661268
Log.w("GLThread", "egl createSurface");
12671269
}
1268-
if (mRegisteredGLSurface.mEglHelper.createSurface()) {
1270+
if (mRegisteredGLSurface.mEglHelper.createSurface(!mSeparateRenderThreadEnabled)) {
12691271
synchronized (sGLThreadManager) {
12701272
mRegisteredGLSurface.mFinishedCreatingEglSurface = true;
12711273
sGLThreadManager.notifyAll();
@@ -1278,6 +1280,7 @@ private void guardedRun() throws InterruptedException {
12781280
}
12791281
continue;
12801282
}
1283+
eglResourcesChanged = true;
12811284
mRegisteredGLSurface.mFrameParams.createEglSurface = false;
12821285
}
12831286

@@ -1302,6 +1305,10 @@ private void guardedRun() throws InterruptedException {
13021305
}
13031306
mRegisteredGLSurface.mFrameParams.sizeChanged = false;
13041307
}
1308+
1309+
if (eglResourcesChanged) {
1310+
mRenderer.onRenderEglResourcesChanged(mRegisteredGLSurface.mEglHelper.mEglDisplay, mRegisteredGLSurface.mEglHelper.mEglSurface, mRegisteredGLSurface.mEglHelper.mEglContext, mRegisteredGLSurface.mEglHelper.mEglConfig);
1311+
}
13051312
}
13061313

13071314
if (LOG_RENDERER_DRAW_FRAME) {
@@ -1588,6 +1595,13 @@ public void queueEvent(Runnable r) {
15881595
}
15891596
}
15901597

1598+
@Override
1599+
public void setSeparateRenderThreadEnabled(boolean enabled) {
1600+
synchronized(sGLThreadManager) {
1601+
mSeparateRenderThreadEnabled = enabled;
1602+
}
1603+
}
1604+
15911605
@Override
15921606
public boolean makeEglCurrent(int id) {
15931607
synchronized (sGLThreadManager) {
@@ -1640,6 +1654,7 @@ public void releaseCurrentGLWindow(int id) {
16401654
private boolean mRequestRender;
16411655
private boolean mWantRenderNotification;
16421656
private boolean mRenderComplete;
1657+
private boolean mSeparateRenderThreadEnabled;
16431658
private final ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
16441659
private Runnable mFinishDrawingRunnable = null;
16451660
private final GodotRenderer mRenderer;

platform/android/java/lib/src/org/godotengine/godot/render/GodotRenderer.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ import android.view.Surface
3737
import org.godotengine.godot.GodotLib
3838
import org.godotengine.godot.plugin.GodotPluginRegistry
3939
import org.godotengine.godot.render.GLSurfaceView.GLThread
40+
import android.opengl.EGLConfig;
41+
import android.opengl.EGLContext;
42+
import android.opengl.EGLDisplay;
43+
import android.opengl.EGLSurface;
4044

4145
/**
4246
* Responsible for setting up and driving Godot rendering logic.
@@ -260,4 +264,9 @@ internal class GodotRenderer(val useVulkan: Boolean) : Renderer {
260264
plugin.onRenderSurfaceCreated(surface)
261265
}
262266
}
267+
268+
override fun onRenderEglResourcesChanged(display: EGLDisplay?, surface: EGLSurface?, context: EGLContext?, config: EGLConfig?) {
269+
GodotLib.updateEglResources(display?.getNativeHandle() ?: 0L, surface?.getNativeHandle() ?: 0L, context?.getNativeHandle() ?: 0L, config?.getNativeHandle() ?: 0L);
270+
}
271+
263272
}

platform/android/java/lib/src/org/godotengine/godot/render/RenderThread.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ internal abstract class RenderThread(tag: String) : Thread(tag) {
8080
*/
8181
open fun surfaceDestroyed(holder: SurfaceHolder) { }
8282

83+
open fun setSeparateRenderThreadEnabled(enabled: Boolean) {}
84+
8385
open fun makeEglCurrent(windowId: Int): Boolean = false
8486

8587
open fun eglSwapBuffers(windowId: Int) {}

platform/android/java/lib/src/org/godotengine/godot/render/Renderer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030

3131
package org.godotengine.godot.render;
3232

33+
import android.opengl.EGLConfig;
34+
import android.opengl.EGLContext;
35+
import android.opengl.EGLDisplay;
36+
import android.opengl.EGLSurface;
3337
import android.view.Surface;
3438

3539
import androidx.annotation.NonNull;
@@ -124,4 +128,9 @@ enum RenderMode {
124128
* Invoked when the render thread is in the process of shutting down.
125129
*/
126130
void onRenderThreadExiting();
131+
132+
/**
133+
* Invoked when any of the EGL resources may have changed.
134+
*/
135+
void onRenderEglResourcesChanged(EGLDisplay display, EGLSurface surface, EGLContext context, EGLConfig config);
127136
}

platform/android/java_godot_lib_jni.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
245245
}
246246
}
247247

248+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateEglResources(JNIEnv *env, jlong p_display, jlong p_surface, jlong p_context, jlong p_config) {
249+
if (DisplayServerAndroid *dsa = DisplayServerAndroid::get_singleton()) {
250+
dsa->update_egl_resources(reinterpret_cast<void *>(p_display), reinterpret_cast<void *>(p_surface), reinterpret_cast<void *>(p_context), reinterpret_cast<void *>(p_config));
251+
}
252+
}
253+
248254
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz) {
249255
if (step.get() <= STEP_SETUP) {
250256
return;

platform/android/java_godot_lib_jni.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
4141
JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline, jobject p_godot_tts);
4242
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height);
4343
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface);
44+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateEglResources(JNIEnv *env, jlong p_display, jlong p_surface, jlong p_context, jlong p_config);
4445
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
4546
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
4647
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);

0 commit comments

Comments
 (0)