BlockingGLTextureView.java revision d8732610ff48dc57063559d55ea3c84775e30e41
1d8732610ff48dc57063559d55ea3c84775e30e41John Reck/* 2d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Copyright (C) 2013 The Android Open Source Project 3d8732610ff48dc57063559d55ea3c84775e30e41John Reck * 4d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5d8732610ff48dc57063559d55ea3c84775e30e41John Reck * you may not use this file except in compliance with the License. 6d8732610ff48dc57063559d55ea3c84775e30e41John Reck * You may obtain a copy of the License at 7d8732610ff48dc57063559d55ea3c84775e30e41John Reck * 8d8732610ff48dc57063559d55ea3c84775e30e41John Reck * http://www.apache.org/licenses/LICENSE-2.0 9d8732610ff48dc57063559d55ea3c84775e30e41John Reck * 10d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Unless required by applicable law or agreed to in writing, software 11d8732610ff48dc57063559d55ea3c84775e30e41John Reck * distributed under the License is distributed on an "AS IS" BASIS, 12d8732610ff48dc57063559d55ea3c84775e30e41John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d8732610ff48dc57063559d55ea3c84775e30e41John Reck * See the License for the specific language governing permissions and 14d8732610ff48dc57063559d55ea3c84775e30e41John Reck * limitations under the License. 15d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 16d8732610ff48dc57063559d55ea3c84775e30e41John Reck 17d8732610ff48dc57063559d55ea3c84775e30e41John Reckpackage com.android.photos.views; 18d8732610ff48dc57063559d55ea3c84775e30e41John Reck 19d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.annotation.SuppressLint; 20d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.content.Context; 21d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.graphics.SurfaceTexture; 22d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.opengl.GLSurfaceView.Renderer; 23d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.opengl.GLUtils; 24d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.util.Log; 25d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.view.TextureView; 26d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport android.view.TextureView.SurfaceTextureListener; 27d8732610ff48dc57063559d55ea3c84775e30e41John Reck 28d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.egl.EGL10; 29d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.egl.EGLConfig; 30d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.egl.EGLContext; 31d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.egl.EGLDisplay; 32d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.egl.EGLSurface; 33d8732610ff48dc57063559d55ea3c84775e30e41John Reckimport javax.microedition.khronos.opengles.GL10; 34d8732610ff48dc57063559d55ea3c84775e30e41John Reck 35d8732610ff48dc57063559d55ea3c84775e30e41John Reck 36d8732610ff48dc57063559d55ea3c84775e30e41John Reckpublic class BlockingGLTextureView extends TextureView 37d8732610ff48dc57063559d55ea3c84775e30e41John Reck implements SurfaceTextureListener { 38d8732610ff48dc57063559d55ea3c84775e30e41John Reck 39d8732610ff48dc57063559d55ea3c84775e30e41John Reck private RenderThread mRenderThread; 40d8732610ff48dc57063559d55ea3c84775e30e41John Reck 41d8732610ff48dc57063559d55ea3c84775e30e41John Reck public BlockingGLTextureView(Context context) { 42d8732610ff48dc57063559d55ea3c84775e30e41John Reck super(context); 43d8732610ff48dc57063559d55ea3c84775e30e41John Reck setSurfaceTextureListener(this); 44d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 45d8732610ff48dc57063559d55ea3c84775e30e41John Reck 46d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void setRenderer(Renderer renderer) { 47d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mRenderThread != null) { 48d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new IllegalArgumentException("Renderer already set"); 49d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 50d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread = new RenderThread(renderer); 51d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 52d8732610ff48dc57063559d55ea3c84775e30e41John Reck 53d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void render() { 54d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.render(); 55d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 56d8732610ff48dc57063559d55ea3c84775e30e41John Reck 57d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void destroy() { 58d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mRenderThread != null) { 59d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.finish(); 60d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread = null; 61d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 62d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 63d8732610ff48dc57063559d55ea3c84775e30e41John Reck 64d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 65d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, 66d8732610ff48dc57063559d55ea3c84775e30e41John Reck int height) { 67d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.setSurface(surface); 68d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.setSize(width, height); 69d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 70d8732610ff48dc57063559d55ea3c84775e30e41John Reck 71d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 72d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, 73d8732610ff48dc57063559d55ea3c84775e30e41John Reck int height) { 74d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.setSize(width, height); 75d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 76d8732610ff48dc57063559d55ea3c84775e30e41John Reck 77d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 78d8732610ff48dc57063559d55ea3c84775e30e41John Reck public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 79d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mRenderThread != null) { 80d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderThread.setSurface(null); 81d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 82d8732610ff48dc57063559d55ea3c84775e30e41John Reck return false; 83d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 84d8732610ff48dc57063559d55ea3c84775e30e41John Reck 85d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 86d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void onSurfaceTextureUpdated(SurfaceTexture surface) { 87d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 88d8732610ff48dc57063559d55ea3c84775e30e41John Reck 89d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 90d8732610ff48dc57063559d55ea3c84775e30e41John Reck protected void finalize() throws Throwable { 91d8732610ff48dc57063559d55ea3c84775e30e41John Reck try { 92d8732610ff48dc57063559d55ea3c84775e30e41John Reck destroy(); 93d8732610ff48dc57063559d55ea3c84775e30e41John Reck } catch (Throwable t) {} 94d8732610ff48dc57063559d55ea3c84775e30e41John Reck super.finalize(); 95d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 96d8732610ff48dc57063559d55ea3c84775e30e41John Reck 97d8732610ff48dc57063559d55ea3c84775e30e41John Reck /** 98d8732610ff48dc57063559d55ea3c84775e30e41John Reck * An EGL helper class. 99d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 100d8732610ff48dc57063559d55ea3c84775e30e41John Reck 101d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static class EglHelper { 102d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 103d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int EGL_OPENGL_ES2_BIT = 4; 104d8732610ff48dc57063559d55ea3c84775e30e41John Reck 105d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10 mEgl; 106d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLDisplay mEglDisplay; 107d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLSurface mEglSurface; 108d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLConfig mEglConfig; 109d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLContext mEglContext; 110d8732610ff48dc57063559d55ea3c84775e30e41John Reck 111d8732610ff48dc57063559d55ea3c84775e30e41John Reck private EGLConfig chooseEglConfig() { 112d8732610ff48dc57063559d55ea3c84775e30e41John Reck int[] configsCount = new int[1]; 113d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLConfig[] configs = new EGLConfig[1]; 114d8732610ff48dc57063559d55ea3c84775e30e41John Reck int[] configSpec = getConfig(); 115d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 116d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new IllegalArgumentException("eglChooseConfig failed " + 117d8732610ff48dc57063559d55ea3c84775e30e41John Reck GLUtils.getEGLErrorString(mEgl.eglGetError())); 118d8732610ff48dc57063559d55ea3c84775e30e41John Reck } else if (configsCount[0] > 0) { 119d8732610ff48dc57063559d55ea3c84775e30e41John Reck return configs[0]; 120d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 121d8732610ff48dc57063559d55ea3c84775e30e41John Reck return null; 122d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 123d8732610ff48dc57063559d55ea3c84775e30e41John Reck 124d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static int[] getConfig() { 125d8732610ff48dc57063559d55ea3c84775e30e41John Reck return new int[] { 126d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 127d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_RED_SIZE, 8, 128d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_GREEN_SIZE, 8, 129d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_BLUE_SIZE, 8, 130d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_ALPHA_SIZE, 8, 131d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_DEPTH_SIZE, 0, 132d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_STENCIL_SIZE, 0, 133d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_NONE 134d8732610ff48dc57063559d55ea3c84775e30e41John Reck }; 135d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 136d8732610ff48dc57063559d55ea3c84775e30e41John Reck 137d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 138d8732610ff48dc57063559d55ea3c84775e30e41John Reck int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 139d8732610ff48dc57063559d55ea3c84775e30e41John Reck return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 140d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 141d8732610ff48dc57063559d55ea3c84775e30e41John Reck 142d8732610ff48dc57063559d55ea3c84775e30e41John Reck /** 143d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Initialize EGL for a given configuration spec. 144d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 145d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void start() { 146d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 147d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Get an EGL instance 148d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 149d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEgl = (EGL10) EGLContext.getEGL(); 150d8732610ff48dc57063559d55ea3c84775e30e41John Reck 151d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 152d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Get to the default display. 153d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 154d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 155d8732610ff48dc57063559d55ea3c84775e30e41John Reck 156d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 157d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException("eglGetDisplay failed"); 158d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 159d8732610ff48dc57063559d55ea3c84775e30e41John Reck 160d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 161d8732610ff48dc57063559d55ea3c84775e30e41John Reck * We can now initialize EGL for that display 162d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 163d8732610ff48dc57063559d55ea3c84775e30e41John Reck int[] version = new int[2]; 164d8732610ff48dc57063559d55ea3c84775e30e41John Reck if(!mEgl.eglInitialize(mEglDisplay, version)) { 165d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException("eglInitialize failed"); 166d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 167d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglConfig = chooseEglConfig(); 168d8732610ff48dc57063559d55ea3c84775e30e41John Reck 169d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 170d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Create an EGL context. We want to do this as rarely as we can, because an 171d8732610ff48dc57063559d55ea3c84775e30e41John Reck * EGL context is a somewhat heavy object. 172d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 173d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 174d8732610ff48dc57063559d55ea3c84775e30e41John Reck 175d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) { 176d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglContext = null; 177d8732610ff48dc57063559d55ea3c84775e30e41John Reck throwEglException("createContext"); 178d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 179d8732610ff48dc57063559d55ea3c84775e30e41John Reck 180d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglSurface = null; 181d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 182d8732610ff48dc57063559d55ea3c84775e30e41John Reck 183d8732610ff48dc57063559d55ea3c84775e30e41John Reck /** 184d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Create an egl surface for the current SurfaceTexture surface. If a surface 185d8732610ff48dc57063559d55ea3c84775e30e41John Reck * already exists, destroy it before creating the new surface. 186d8732610ff48dc57063559d55ea3c84775e30e41John Reck * 187d8732610ff48dc57063559d55ea3c84775e30e41John Reck * @return true if the surface was created successfully. 188d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 189d8732610ff48dc57063559d55ea3c84775e30e41John Reck public boolean createSurface(SurfaceTexture surface) { 190d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 191d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Check preconditions. 192d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 193d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEgl == null) { 194d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException("egl not initialized"); 195d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 196d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglDisplay == null) { 197d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException("eglDisplay not initialized"); 198d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 199d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglConfig == null) { 200d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException("mEglConfig not initialized"); 201d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 202d8732610ff48dc57063559d55ea3c84775e30e41John Reck 203d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 204d8732610ff48dc57063559d55ea3c84775e30e41John Reck * The window size has changed, so we need to create a new 205d8732610ff48dc57063559d55ea3c84775e30e41John Reck * surface. 206d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 207d8732610ff48dc57063559d55ea3c84775e30e41John Reck destroySurfaceImp(); 208d8732610ff48dc57063559d55ea3c84775e30e41John Reck 209d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 210d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Create an EGL surface we can render into. 211d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 212d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (surface != null) { 213d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null); 214d8732610ff48dc57063559d55ea3c84775e30e41John Reck } else { 215d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglSurface = null; 216d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 217d8732610ff48dc57063559d55ea3c84775e30e41John Reck 218d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 219d8732610ff48dc57063559d55ea3c84775e30e41John Reck int error = mEgl.eglGetError(); 220d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 221d8732610ff48dc57063559d55ea3c84775e30e41John Reck Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 222d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 223d8732610ff48dc57063559d55ea3c84775e30e41John Reck return false; 224d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 225d8732610ff48dc57063559d55ea3c84775e30e41John Reck 226d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 227d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Before we can issue GL commands, we need to make sure 228d8732610ff48dc57063559d55ea3c84775e30e41John Reck * the context is current and bound to a surface. 229d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 230d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 231d8732610ff48dc57063559d55ea3c84775e30e41John Reck /* 232d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Could not make the context current, probably because the underlying 233d8732610ff48dc57063559d55ea3c84775e30e41John Reck * SurfaceView surface has been destroyed. 234d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 235d8732610ff48dc57063559d55ea3c84775e30e41John Reck logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError()); 236d8732610ff48dc57063559d55ea3c84775e30e41John Reck return false; 237d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 238d8732610ff48dc57063559d55ea3c84775e30e41John Reck 239d8732610ff48dc57063559d55ea3c84775e30e41John Reck return true; 240d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 241d8732610ff48dc57063559d55ea3c84775e30e41John Reck 242d8732610ff48dc57063559d55ea3c84775e30e41John Reck /** 243d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Create a GL object for the current EGL context. 244d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 245d8732610ff48dc57063559d55ea3c84775e30e41John Reck public GL10 createGL() { 246d8732610ff48dc57063559d55ea3c84775e30e41John Reck return (GL10) mEglContext.getGL(); 247d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 248d8732610ff48dc57063559d55ea3c84775e30e41John Reck 249d8732610ff48dc57063559d55ea3c84775e30e41John Reck /** 250d8732610ff48dc57063559d55ea3c84775e30e41John Reck * Display the current render surface. 251d8732610ff48dc57063559d55ea3c84775e30e41John Reck * @return the EGL error code from eglSwapBuffers. 252d8732610ff48dc57063559d55ea3c84775e30e41John Reck */ 253d8732610ff48dc57063559d55ea3c84775e30e41John Reck public int swap() { 254d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 255d8732610ff48dc57063559d55ea3c84775e30e41John Reck return mEgl.eglGetError(); 256d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 257d8732610ff48dc57063559d55ea3c84775e30e41John Reck return EGL10.EGL_SUCCESS; 258d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 259d8732610ff48dc57063559d55ea3c84775e30e41John Reck 260d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void destroySurface() { 261d8732610ff48dc57063559d55ea3c84775e30e41John Reck destroySurfaceImp(); 262d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 263d8732610ff48dc57063559d55ea3c84775e30e41John Reck 264d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void destroySurfaceImp() { 265d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) { 266d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, 267d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_NO_SURFACE, 268d8732610ff48dc57063559d55ea3c84775e30e41John Reck EGL10.EGL_NO_CONTEXT); 269d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 270d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglSurface = null; 271d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 272d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 273d8732610ff48dc57063559d55ea3c84775e30e41John Reck 274d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void finish() { 275d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglContext != null) { 276d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEgl.eglDestroyContext(mEglDisplay, mEglContext); 277d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglContext = null; 278d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 279d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglDisplay != null) { 280d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEgl.eglTerminate(mEglDisplay); 281d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglDisplay = null; 282d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 283d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 284d8732610ff48dc57063559d55ea3c84775e30e41John Reck 285d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void throwEglException(String function) { 286d8732610ff48dc57063559d55ea3c84775e30e41John Reck throwEglException(function, mEgl.eglGetError()); 287d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 288d8732610ff48dc57063559d55ea3c84775e30e41John Reck 289d8732610ff48dc57063559d55ea3c84775e30e41John Reck public static void throwEglException(String function, int error) { 290d8732610ff48dc57063559d55ea3c84775e30e41John Reck String message = formatEglError(function, error); 291d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new RuntimeException(message); 292d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 293d8732610ff48dc57063559d55ea3c84775e30e41John Reck 294d8732610ff48dc57063559d55ea3c84775e30e41John Reck public static void logEglErrorAsWarning(String tag, String function, int error) { 295d8732610ff48dc57063559d55ea3c84775e30e41John Reck Log.w(tag, formatEglError(function, error)); 296d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 297d8732610ff48dc57063559d55ea3c84775e30e41John Reck 298d8732610ff48dc57063559d55ea3c84775e30e41John Reck public static String formatEglError(String function, int error) { 299d8732610ff48dc57063559d55ea3c84775e30e41John Reck return function + " failed: " + error; 300d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 301d8732610ff48dc57063559d55ea3c84775e30e41John Reck 302d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 303d8732610ff48dc57063559d55ea3c84775e30e41John Reck 304d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static class RenderThread extends Thread { 305d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int INVALID = -1; 306d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int RENDER = 1; 307d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int CHANGE_SURFACE = 2; 308d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int RESIZE_SURFACE = 3; 309d8732610ff48dc57063559d55ea3c84775e30e41John Reck private static final int FINISH = 4; 310d8732610ff48dc57063559d55ea3c84775e30e41John Reck 311d8732610ff48dc57063559d55ea3c84775e30e41John Reck private EglHelper mEglHelper = new EglHelper(); 312d8732610ff48dc57063559d55ea3c84775e30e41John Reck 313d8732610ff48dc57063559d55ea3c84775e30e41John Reck private Object mLock = new Object(); 314d8732610ff48dc57063559d55ea3c84775e30e41John Reck private int mExecMsgId = INVALID; 315d8732610ff48dc57063559d55ea3c84775e30e41John Reck private SurfaceTexture mSurface; 316d8732610ff48dc57063559d55ea3c84775e30e41John Reck private Renderer mRenderer; 317d8732610ff48dc57063559d55ea3c84775e30e41John Reck private int mWidth, mHeight; 318d8732610ff48dc57063559d55ea3c84775e30e41John Reck 319d8732610ff48dc57063559d55ea3c84775e30e41John Reck private boolean mFinished = false; 320d8732610ff48dc57063559d55ea3c84775e30e41John Reck private GL10 mGL; 321d8732610ff48dc57063559d55ea3c84775e30e41John Reck 322d8732610ff48dc57063559d55ea3c84775e30e41John Reck public RenderThread(Renderer renderer) { 323d8732610ff48dc57063559d55ea3c84775e30e41John Reck super("RenderThread"); 324d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderer = renderer; 325d8732610ff48dc57063559d55ea3c84775e30e41John Reck start(); 326d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 327d8732610ff48dc57063559d55ea3c84775e30e41John Reck 328d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void checkRenderer() { 329d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mRenderer == null) { 330d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new IllegalArgumentException("Renderer is null!"); 331d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 332d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 333d8732610ff48dc57063559d55ea3c84775e30e41John Reck 334d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void checkSurface() { 335d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mSurface == null) { 336d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new IllegalArgumentException("surface is null!"); 337d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 338d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 339d8732610ff48dc57063559d55ea3c84775e30e41John Reck 340d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void setSurface(SurfaceTexture surface) { 341d8732610ff48dc57063559d55ea3c84775e30e41John Reck // If the surface is null we're being torn down, don't need a 342d8732610ff48dc57063559d55ea3c84775e30e41John Reck // renderer then 343d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (surface != null) { 344d8732610ff48dc57063559d55ea3c84775e30e41John Reck checkRenderer(); 345d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 346d8732610ff48dc57063559d55ea3c84775e30e41John Reck mSurface = surface; 347d8732610ff48dc57063559d55ea3c84775e30e41John Reck exec(CHANGE_SURFACE); 348d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 349d8732610ff48dc57063559d55ea3c84775e30e41John Reck 350d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void setSize(int width, int height) { 351d8732610ff48dc57063559d55ea3c84775e30e41John Reck checkRenderer(); 352d8732610ff48dc57063559d55ea3c84775e30e41John Reck checkSurface(); 353d8732610ff48dc57063559d55ea3c84775e30e41John Reck mWidth = width; 354d8732610ff48dc57063559d55ea3c84775e30e41John Reck mHeight = height; 355d8732610ff48dc57063559d55ea3c84775e30e41John Reck exec(RESIZE_SURFACE); 356d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 357d8732610ff48dc57063559d55ea3c84775e30e41John Reck 358d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void render() { 359d8732610ff48dc57063559d55ea3c84775e30e41John Reck checkRenderer(); 360d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mSurface != null) { 361d8732610ff48dc57063559d55ea3c84775e30e41John Reck exec(RENDER); 362d8732610ff48dc57063559d55ea3c84775e30e41John Reck mSurface.updateTexImage(); 363d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 364d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 365d8732610ff48dc57063559d55ea3c84775e30e41John Reck 366d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void finish() { 367d8732610ff48dc57063559d55ea3c84775e30e41John Reck mSurface = null; 368d8732610ff48dc57063559d55ea3c84775e30e41John Reck exec(FINISH); 369d8732610ff48dc57063559d55ea3c84775e30e41John Reck try { 370d8732610ff48dc57063559d55ea3c84775e30e41John Reck join(); 371d8732610ff48dc57063559d55ea3c84775e30e41John Reck } catch (InterruptedException e) {} 372d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 373d8732610ff48dc57063559d55ea3c84775e30e41John Reck 374d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void exec(int msgid) { 375d8732610ff48dc57063559d55ea3c84775e30e41John Reck synchronized (mLock) { 376d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mExecMsgId != INVALID) { 377d8732610ff48dc57063559d55ea3c84775e30e41John Reck throw new IllegalArgumentException("Message already set - multithreaded access?"); 378d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 379d8732610ff48dc57063559d55ea3c84775e30e41John Reck mExecMsgId = msgid; 380d8732610ff48dc57063559d55ea3c84775e30e41John Reck mLock.notify(); 381d8732610ff48dc57063559d55ea3c84775e30e41John Reck try { 382d8732610ff48dc57063559d55ea3c84775e30e41John Reck mLock.wait(); 383d8732610ff48dc57063559d55ea3c84775e30e41John Reck } catch (InterruptedException e) {} 384d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 385d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 386d8732610ff48dc57063559d55ea3c84775e30e41John Reck 387d8732610ff48dc57063559d55ea3c84775e30e41John Reck private void handleMessageLocked(int what) { 388d8732610ff48dc57063559d55ea3c84775e30e41John Reck switch (what) { 389d8732610ff48dc57063559d55ea3c84775e30e41John Reck case CHANGE_SURFACE: 390d8732610ff48dc57063559d55ea3c84775e30e41John Reck if (mEglHelper.createSurface(mSurface)) { 391d8732610ff48dc57063559d55ea3c84775e30e41John Reck mGL = mEglHelper.createGL(); 392d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig); 393d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 394d8732610ff48dc57063559d55ea3c84775e30e41John Reck break; 395d8732610ff48dc57063559d55ea3c84775e30e41John Reck case RESIZE_SURFACE: 396d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderer.onSurfaceChanged(mGL, mWidth, mHeight); 397d8732610ff48dc57063559d55ea3c84775e30e41John Reck break; 398d8732610ff48dc57063559d55ea3c84775e30e41John Reck case RENDER: 399d8732610ff48dc57063559d55ea3c84775e30e41John Reck mRenderer.onDrawFrame(mGL); 400d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglHelper.swap(); 401d8732610ff48dc57063559d55ea3c84775e30e41John Reck break; 402d8732610ff48dc57063559d55ea3c84775e30e41John Reck case FINISH: 403d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglHelper.destroySurface(); 404d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglHelper.finish(); 405d8732610ff48dc57063559d55ea3c84775e30e41John Reck mFinished = true; 406d8732610ff48dc57063559d55ea3c84775e30e41John Reck break; 407d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 408d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 409d8732610ff48dc57063559d55ea3c84775e30e41John Reck 410d8732610ff48dc57063559d55ea3c84775e30e41John Reck @Override 411d8732610ff48dc57063559d55ea3c84775e30e41John Reck public void run() { 412d8732610ff48dc57063559d55ea3c84775e30e41John Reck synchronized (mLock) { 413d8732610ff48dc57063559d55ea3c84775e30e41John Reck mEglHelper.start(); 414d8732610ff48dc57063559d55ea3c84775e30e41John Reck while (!mFinished) { 415d8732610ff48dc57063559d55ea3c84775e30e41John Reck while (mExecMsgId == INVALID) { 416d8732610ff48dc57063559d55ea3c84775e30e41John Reck try { 417d8732610ff48dc57063559d55ea3c84775e30e41John Reck mLock.wait(); 418d8732610ff48dc57063559d55ea3c84775e30e41John Reck } catch (InterruptedException e) {} 419d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 420d8732610ff48dc57063559d55ea3c84775e30e41John Reck handleMessageLocked(mExecMsgId); 421d8732610ff48dc57063559d55ea3c84775e30e41John Reck mExecMsgId = INVALID; 422d8732610ff48dc57063559d55ea3c84775e30e41John Reck mLock.notify(); 423d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 424d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 425d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 426d8732610ff48dc57063559d55ea3c84775e30e41John Reck } 427d8732610ff48dc57063559d55ea3c84775e30e41John Reck} 428