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