@@ -69,7 +69,10 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
6969 internal var surface: Surface ? = null
7070 @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
7171 internal var eglSurface: EGLSurface
72+
73+ @RenderThread
7274 private var width: Int = 0
75+ @RenderThread
7376 private var height: Int = 0
7477
7578 private val widgetRenderer: MapboxWidgetRenderer
@@ -80,7 +83,6 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
8083 @Volatile
8184 @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
8285 internal var awaitingNextVsync = false
83- private var sizeChanged = false
8486 @Volatile
8587 @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
8688 internal var paused = false
@@ -119,9 +121,10 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
119121 * Render thread should be treated as valid (prepared to render a map) when both flags are true.
120122 * Getter is thread-safe as this flag could be accessed from any thread.
121123 */
122- private val renderThreadPrepared get() = renderThreadPreparedLock.withLock {
123- eglContextMadeCurrent && nativeRenderCreated
124- }
124+ private val renderThreadPrepared
125+ get() = renderThreadPreparedLock.withLock {
126+ eglContextMadeCurrent && nativeRenderCreated
127+ }
125128 private var eglContextCreated = false
126129 private var renderNotSupported = false
127130
@@ -223,7 +226,7 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
223226 * Keep a runnable to [prepareRenderFrame] to avoid creating a new one on every frame.
224227 */
225228 private val prepareRenderFrameRunnable: Runnable = Runnable {
226- prepareRenderFrame()
229+ prepareRenderFrame(width = null , height = null , creatingSurface = false )
227230 }
228231 private fun postPrepareRenderFrame (delayMillis : Long = 0L) {
229232 renderHandlerThread.postDelayed(
@@ -265,10 +268,6 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
265268 nativeRenderCreated = true
266269 mapboxRenderer.createRenderer()
267270 logI(TAG , " Native renderer created." )
268- mapboxRenderer.onSurfaceChanged(
269- width = width,
270- height = height
271- )
272271 }
273272 return true
274273 }
@@ -336,12 +335,10 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
336335 return true
337336 }
338337
339- private fun checkSurfaceSizeChanged () {
340- if (sizeChanged ) {
338+ @RenderThread
339+ private fun notifyRenderersSizeChanged ( width : Int , height : Int ) {
341340 mapboxRenderer.onSurfaceChanged(width = width, height = height)
342341 widgetRenderer.onSurfaceChanged(width = width, height = height)
343- sizeChanged = false
344- }
345342 }
346343
347344 private fun checkWidgetRender () {
@@ -470,18 +467,34 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
470467 }
471468 eglContextCreated = false
472469 if (tryRecreate) {
473- setUpRenderThread(creatingSurface = true )
470+ if (setUpRenderThread(creatingSurface = true )) {
471+ notifyRenderersSizeChanged(width, height)
472+ }
474473 } else {
475474 surface?.release()
476475 }
477476 }
478477 }
479478
480- private fun prepareRenderFrame (creatingSurface : Boolean = false) {
481- // no need to do anything if we're waiting for next VSYNC already;
479+ /* *
480+ * Responsible to prepare for rendering and schedule a new frame render (synchronized with the
481+ * display's refresh rate using [Choreographer]).
482+ * There are 3 main reasons to request a new frame:
483+ * 1. A new surface is available ([creatingSurface] flag is true and [width] and [height] are given).
484+ * 2. The surface was resized (new [width] and [height] are given).
485+ * 3. Normal render pass ([creatingSurface] flag is false and no sizes are given).
486+ */
487+ @RenderThread
488+ private fun prepareRenderFrame (
489+ width : Int? ,
490+ height : Int? ,
491+ creatingSurface : Boolean
492+ ) {
493+ // no need to do anything if we're already waiting for next VSYNC (`doFrame`);
482494 // however if Android has sent us new surface - we must proceed up to `setUpRenderThread` or
483495 // otherwise main thread will end up having deadlock
484- if (awaitingNextVsync && ! creatingSurface) {
496+ // We also should go through if we've new sizes to set
497+ if (awaitingNextVsync && ! creatingSurface && width == null && height == null ) {
485498 return
486499 }
487500 // Check first if we have to stop rendering at all (even if there was no EGL config) and cleanup EGL.
@@ -515,19 +528,21 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
515528 }
516529 }
517530 checkWidgetRender()
518- checkSurfaceSizeChanged()
531+ if (width != null && height != null && renderThreadPrepared) {
532+ notifyRenderersSizeChanged(width, height)
533+ }
519534 Choreographer .getInstance().postFrameCallback(this )
520535 awaitingNextVsync = true
521536 }
522537
523538 @UiThread
524539 fun onSurfaceSizeChanged (width : Int , height : Int ) {
525- if ( this .width != width || this .height != height) {
526- renderHandlerThread.post {
540+ renderHandlerThread.post {
541+ if ( this .width != width || this .height != height) {
527542 this @MapboxRenderThread.width = width
528543 this @MapboxRenderThread.height = height
529- sizeChanged = true
530- prepareRenderFrame()
544+ // Schedule a new frame to draw map with the new size
545+ prepareRenderFrame(width = width, height = height, creatingSurface = false )
531546 }
532547 }
533548 }
@@ -586,8 +601,8 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
586601 }
587602 this .width = width
588603 this .height = height
589- widgetRenderer.onSurfaceChanged(width = width, height = height)
590- prepareRenderFrame(creatingSurface = true )
604+ // Make sure we initialize renderer and schedule next frame to draw map.
605+ prepareRenderFrame(width, height, creatingSurface = true )
591606 }
592607
593608 @UiThread
@@ -604,6 +619,8 @@ internal class MapboxRenderThread : Choreographer.FrameCallback {
604619 surfaceProcessingLock.withLock {
605620 if (renderHandlerThread.isRunning) {
606621 renderHandlerThread.post {
622+ this .width = width
623+ this .height = height
607624 processAndroidSurface(surface, width, height)
608625 }
609626 logI(TAG , " onSurfaceCreated: waiting Android surface to be processed..." )
0 commit comments