diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java')
-rw-r--r-- | platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java | 470 |
1 files changed, 0 insertions, 470 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java deleted file mode 100644 index 205e35641b..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ /dev/null @@ -1,470 +0,0 @@ -package com.mapbox.mapboxsdk.maps.renderer.textureview; - -import android.graphics.SurfaceTexture; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.UiThread; -import android.view.TextureView; - -import com.mapbox.mapboxsdk.log.Logger; -import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGL11; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.egl.EGLSurface; -import javax.microedition.khronos.opengles.GL10; - -/** - * The render thread is responsible for managing the communication between the - * ui thread and the render thread it creates. Also, the EGL and GL contexts - * are managed from here. - */ -class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextureListener { - - private static final String TAG = "Mbgl-TextureViewRenderThread"; - - @NonNull - private final TextureViewMapRenderer mapRenderer; - @NonNull - private final EGLHolder eglHolder; - - // Lock used for synchronization - private final Object lock = new Object(); - - // Guarded by lock - private final ArrayList<Runnable> eventQueue = new ArrayList<>(); - @Nullable - private SurfaceTexture surface; - private int width; - private int height; - private boolean requestRender; - private boolean sizeChanged; - private boolean paused; - private boolean destroyContext; - private boolean destroySurface; - private boolean shouldExit; - private boolean exited; - - /** - * Create a render thread for the given TextureView / Maprenderer combination. - * - * @param textureView the TextureView - * @param mapRenderer the MapRenderer - */ - @UiThread - TextureViewRenderThread(@NonNull TextureView textureView, @NonNull TextureViewMapRenderer mapRenderer) { - textureView.setOpaque(!mapRenderer.isTranslucentSurface()); - textureView.setSurfaceTextureListener(this); - this.mapRenderer = mapRenderer; - this.eglHolder = new EGLHolder(new WeakReference<>(textureView), mapRenderer.isTranslucentSurface()); - } - - // SurfaceTextureListener methods - - @UiThread - @Override - public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) { - synchronized (lock) { - this.surface = surface; - this.width = width; - this.height = height; - this.requestRender = true; - lock.notifyAll(); - } - } - - @Override - @UiThread - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, final int width, final int height) { - synchronized (lock) { - this.width = width; - this.height = height; - this.sizeChanged = true; - this.requestRender = true; - lock.notifyAll(); - } - } - - @Override - @UiThread - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - synchronized (lock) { - this.surface = null; - this.destroySurface = true; - this.requestRender = false; - lock.notifyAll(); - } - return true; - } - - @Override - @UiThread - public void onSurfaceTextureUpdated(SurfaceTexture surface) { - // Ignored - } - - // MapRenderer delegate methods - - /** - * May be called from any thread - */ - void requestRender() { - synchronized (lock) { - requestRender = true; - lock.notifyAll(); - } - } - - /** - * May be called from any thread - */ - void queueEvent(@NonNull Runnable runnable) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); - } - synchronized (lock) { - eventQueue.add(runnable); - lock.notifyAll(); - } - } - - - @UiThread - void onPause() { - synchronized (lock) { - this.paused = true; - lock.notifyAll(); - } - } - - @UiThread - void onResume() { - synchronized (lock) { - this.paused = false; - lock.notifyAll(); - } - } - - - @UiThread - void onDestroy() { - synchronized (lock) { - this.shouldExit = true; - lock.notifyAll(); - - // Wait for the thread to exit - while (!this.exited) { - try { - lock.wait(); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - } - - // Thread implementation - - @Override - public void run() { - try { - - while (true) { - Runnable event = null; - boolean initializeEGL = false; - boolean recreateSurface = false; - int w = -1; - int h = -1; - - // Guarded block - synchronized (lock) { - while (true) { - - if (shouldExit) { - return; - } - - // If any events are scheduled, pop one for processing - if (!eventQueue.isEmpty()) { - event = eventQueue.remove(0); - break; - } - - if (destroySurface) { - eglHolder.destroySurface(); - destroySurface = false; - break; - } - - if (destroyContext) { - eglHolder.destroyContext(); - destroyContext = false; - break; - } - - if (surface != null && !paused && requestRender) { - - w = width; - h = height; - - // Initialize EGL if needed - if (eglHolder.eglContext == EGL10.EGL_NO_CONTEXT) { - initializeEGL = true; - break; - } - - // (re-)Initialize EGL Surface if needed - if (eglHolder.eglSurface == EGL10.EGL_NO_SURFACE) { - recreateSurface = true; - break; - } - - // Reset the request render flag now, so we can catch new requests - // while rendering - requestRender = false; - - // Break the guarded loop and continue to process - break; - } - - - // Wait until needed - lock.wait(); - - } // end guarded while loop - - } // end guarded block - - // Run event, if any - if (event != null) { - event.run(); - continue; - } - - GL10 gl = eglHolder.createGL(); - - // Initialize EGL - if (initializeEGL) { - eglHolder.prepare(); - synchronized (lock) { - if (!eglHolder.createSurface()) { - // Cleanup the surface if one could not be created - // and wait for another to be ready. - destroySurface = true; - continue; - } - } - mapRenderer.onSurfaceCreated(gl, eglHolder.eglConfig); - mapRenderer.onSurfaceChanged(gl, w, h); - continue; - } - - // If the surface size has changed inform the map renderer. - if (recreateSurface) { - synchronized (lock) { - eglHolder.createSurface(); - } - mapRenderer.onSurfaceChanged(gl, w, h); - continue; - } - - if (sizeChanged) { - mapRenderer.onSurfaceChanged(gl, w, h); - sizeChanged = false; - continue; - } - - // Don't continue without a surface - if (eglHolder.eglSurface == EGL10.EGL_NO_SURFACE) { - continue; - } - - // Time to render a frame - mapRenderer.onDrawFrame(gl); - - // Swap and check the result - int swapError = eglHolder.swap(); - switch (swapError) { - case EGL10.EGL_SUCCESS: - break; - case EGL11.EGL_CONTEXT_LOST: - Logger.w(TAG, "Context lost. Waiting for re-aquire"); - synchronized (lock) { - surface = null; - destroySurface = true; - destroyContext = true; - } - break; - default: - Logger.w(TAG, String.format("eglSwapBuffer error: %s. Waiting or new surface", swapError)); - // Probably lost the surface. Clear the current one and - // wait for a new one to be set - synchronized (lock) { - surface = null; - destroySurface = true; - } - } - - } - - } catch (InterruptedException err) { - // To be expected - } finally { - // Cleanup - eglHolder.cleanup(); - - // Signal we're done - synchronized (lock) { - this.exited = true; - lock.notifyAll(); - } - } - } - - /** - * Holds the EGL state and offers methods to mutate it. - */ - private static class EGLHolder { - private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - private final WeakReference<TextureView> textureViewWeakRef; - private boolean translucentSurface; - - private EGL10 egl; - @Nullable - private EGLConfig eglConfig; - private EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; - private EGLContext eglContext = EGL10.EGL_NO_CONTEXT; - private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; - - EGLHolder(WeakReference<TextureView> textureViewWeakRef, boolean translucentSurface) { - this.textureViewWeakRef = textureViewWeakRef; - this.translucentSurface = translucentSurface; - } - - void prepare() { - this.egl = (EGL10) EGLContext.getEGL(); - - // Only re-initialize display when needed - if (eglDisplay == EGL10.EGL_NO_DISPLAY) { - this.eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - if (eglDisplay == EGL10.EGL_NO_DISPLAY) { - throw new RuntimeException("eglGetDisplay failed"); - } - - int[] version = new int[2]; - if (!egl.eglInitialize(eglDisplay, version)) { - throw new RuntimeException("eglInitialize failed"); - } - } - - if (textureViewWeakRef == null) { - // No texture view present - eglConfig = null; - eglContext = EGL10.EGL_NO_CONTEXT; - } else if (eglContext == EGL10.EGL_NO_CONTEXT) { - eglConfig = new EGLConfigChooser(translucentSurface).chooseConfig(egl, eglDisplay); - int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; - eglContext = egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); - } - - if (eglContext == EGL10.EGL_NO_CONTEXT) { - throw new RuntimeException("createContext"); - } - } - - @NonNull - GL10 createGL() { - return (GL10) eglContext.getGL(); - } - - boolean createSurface() { - // The window size has changed, so we need to create a new surface. - destroySurface(); - - // Create an EGL surface we can render into. - TextureView view = textureViewWeakRef.get(); - if (view != null) { - int[] surfaceAttribs = {EGL10.EGL_NONE}; - eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, view.getSurfaceTexture(), surfaceAttribs); - } else { - eglSurface = EGL10.EGL_NO_SURFACE; - } - - if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) { - int error = egl.eglGetError(); - if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { - Logger.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); - } - return false; - } - - return makeCurrent(); - } - - boolean makeCurrent() { - if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { - // Could not make the context current, probably because the underlying - // SurfaceView surface has been destroyed. - Logger.w(TAG, String.format("eglMakeCurrent: %s", egl.eglGetError())); - return false; - } - - return true; - } - - int swap() { - if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) { - return egl.eglGetError(); - } - return EGL10.EGL_SUCCESS; - } - - private void destroySurface() { - if (eglSurface == EGL10.EGL_NO_SURFACE) { - return; - } - - if (!egl.eglDestroySurface(eglDisplay, eglSurface)) { - Logger.w(TAG, String.format("Could not destroy egl surface. Display %s, Surface %s", eglDisplay, eglSurface)); - } - - eglSurface = EGL10.EGL_NO_SURFACE; - } - - private void destroyContext() { - if (eglContext == EGL10.EGL_NO_CONTEXT) { - return; - } - - if (!egl.eglDestroyContext(eglDisplay, eglContext)) { - Logger.w(TAG, String.format("Could not destroy egl context. Display %s, Context %s", eglDisplay, eglContext)); - } - - eglContext = EGL10.EGL_NO_CONTEXT; - } - - private void terminate() { - if (eglDisplay == EGL10.EGL_NO_DISPLAY) { - return; - } - - if (!egl.eglTerminate(eglDisplay)) { - Logger.w(TAG, String.format("Could not terminate egl. Display %s", eglDisplay)); - } - eglDisplay = EGL10.EGL_NO_DISPLAY; - } - - void cleanup() { - destroySurface(); - destroyContext(); - terminate(); - } - } -} |