From 9e9a2bd5555b226528d70bd35140afe28397a0e5 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Mon, 15 Jan 2024 14:39:50 +0100 Subject: [PATCH 1/3] Call glFinish on render breaks --- .../mapscore/graphics/GLThread.kt | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt index 50bbddd82..c2008e38c 100644 --- a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt +++ b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt @@ -16,6 +16,7 @@ import android.util.Log import io.openmobilemaps.mapscore.BuildConfig import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong import javax.microedition.khronos.egl.* import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.egl.EGLContext @@ -38,6 +39,10 @@ class GLThread constructor( private const val TAG = "GLThread" private const val EGL_OPENGL_ES3_BIT = 0x00000040 + private const val PAUSE_RENDER_INTERVAL = 30000L + private const val BREAK_RENDER_INTERVAL = 1000L + private const val BREAK_MIN_FINISH_MS = BREAK_RENDER_INTERVAL / 2 + const val MAX_NUM_GRAPHICS_PRE_TASKS = 16 private val defaultConfig = intArrayOf( @@ -69,6 +74,8 @@ class GLThread constructor( val runNotifier = Object() var glRunList = ConcurrentLinkedQueue<() -> Unit>() val isDirty = AtomicBoolean(false) + val lastDirtyTimestamp = AtomicLong(0) + var hasFinishedSinceDirty = false var renderer: GLSurfaceView.Renderer? = null var surface: SurfaceTexture? = null @@ -106,12 +113,23 @@ class GLThread constructor( if ((!isDirty.get() && glRunList.isEmpty()) || isPaused) { var wasPaused = false do { + var firstPause = false if (isPaused && !wasPaused) { onPauseCallback?.invoke() wasPaused = true + firstPause = true + } + val preFinish = System.currentTimeMillis() + if (firstPause || (!hasFinishedSinceDirty && preFinish - lastDirtyTimestamp.get() > BREAK_MIN_FINISH_MS)) { + GLES32.glFinish() + hasFinishedSinceDirty = true } + val finishDuration = System.currentTimeMillis() - preFinish + try { - synchronized(runNotifier) { runNotifier.wait(1000) } + if (finishDuration < BREAK_RENDER_INTERVAL) { + synchronized(runNotifier) { runNotifier.wait(if (isPaused) PAUSE_RENDER_INTERVAL else BREAK_RENDER_INTERVAL - finishDuration) } + } } catch (e: InterruptedException) { e.printStackTrace() } @@ -360,7 +378,10 @@ class GLThread constructor( } fun requestRender() { + lastDirtyTimestamp.set(System.currentTimeMillis()) + hasFinishedSinceDirty = false isDirty.set(true) + synchronized(runNotifier) { runNotifier.notify() } } From 45a4ffbb7d272807001698deb1a59f63d3d8b9fc Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Mon, 22 Jan 2024 08:42:27 +0100 Subject: [PATCH 2/3] Keep rendering for some time before break --- .../io/openmobilemaps/mapscore/graphics/GLThread.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt index c2008e38c..129a5da82 100644 --- a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt +++ b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt @@ -110,7 +110,7 @@ class GLThread constructor( } while (!finished) { - if ((!isDirty.get() && glRunList.isEmpty()) || isPaused) { + if ((!isDirty.get() && glRunList.isEmpty()) && (isPaused || System.currentTimeMillis() - lastDirtyTimestamp.get() > BREAK_MIN_FINISH_MS)) { var wasPaused = false do { var firstPause = false @@ -119,12 +119,13 @@ class GLThread constructor( wasPaused = true firstPause = true } - val preFinish = System.currentTimeMillis() - if (firstPause || (!hasFinishedSinceDirty && preFinish - lastDirtyTimestamp.get() > BREAK_MIN_FINISH_MS)) { + var finishDuration = 0L + if (firstPause || !hasFinishedSinceDirty) { + finishDuration = System.currentTimeMillis() GLES32.glFinish() hasFinishedSinceDirty = true + finishDuration = System.currentTimeMillis() - finishDuration } - val finishDuration = System.currentTimeMillis() - preFinish try { if (finishDuration < BREAK_RENDER_INTERVAL) { @@ -154,7 +155,6 @@ class GLThread constructor( glRunList.poll()?.invoke() i++ } - renderer.onDrawFrame(gl10) if (BuildConfig.DEBUG) { GLES32.glGetError().let { @@ -381,7 +381,6 @@ class GLThread constructor( lastDirtyTimestamp.set(System.currentTimeMillis()) hasFinishedSinceDirty = false isDirty.set(true) - synchronized(runNotifier) { runNotifier.notify() } } From 13e2c711a68f98ada20638dd88d79cf1004211d2 Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 24 Jan 2024 11:36:16 +0100 Subject: [PATCH 3/3] Refactor and prevent pause stalling --- .../main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt index 129a5da82..9eba701dd 100644 --- a/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt +++ b/android/src/main/java/io/openmobilemaps/mapscore/graphics/GLThread.kt @@ -110,7 +110,8 @@ class GLThread constructor( } while (!finished) { - if ((!isDirty.get() && glRunList.isEmpty()) && (isPaused || System.currentTimeMillis() - lastDirtyTimestamp.get() > BREAK_MIN_FINISH_MS)) { + val isAfterBreakMinThreshold = System.currentTimeMillis() - lastDirtyTimestamp.get() > BREAK_MIN_FINISH_MS + if ((!isDirty.get() && glRunList.isEmpty() && isAfterBreakMinThreshold) || isPaused) { var wasPaused = false do { var firstPause = false