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