GLTextureViewActivity.java revision 80429c458506485904715180d10584092a5cd082
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.test.hwui; 18 19import android.animation.ObjectAnimator; 20import android.animation.ValueAnimator; 21import android.app.Activity; 22import android.graphics.SurfaceTexture; 23import android.opengl.GLES20; 24import android.os.Bundle; 25import android.util.Log; 26import android.view.Gravity; 27import android.view.TextureView; 28import android.view.View; 29import android.widget.FrameLayout; 30 31import javax.microedition.khronos.egl.EGL10; 32import javax.microedition.khronos.egl.EGL11; 33import javax.microedition.khronos.egl.EGLConfig; 34import javax.microedition.khronos.egl.EGLContext; 35import javax.microedition.khronos.egl.EGLDisplay; 36import javax.microedition.khronos.egl.EGLSurface; 37import javax.microedition.khronos.opengles.GL; 38 39@SuppressWarnings({"UnusedDeclaration"}) 40public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener { 41 private RenderThread mRenderThread; 42 private TextureView mTextureView; 43 44 @Override 45 protected void onCreate(Bundle savedInstanceState) { 46 super.onCreate(savedInstanceState); 47 48 mTextureView = new TextureView(this); 49 mTextureView.setSurfaceTextureListener(this); 50 51 setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER)); 52 } 53 54 @Override 55 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 56 mRenderThread = new RenderThread(surface); 57 mRenderThread.start(); 58 59 mTextureView.setCameraDistance(5000); 60 61 ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f); 62 animator.setRepeatMode(ObjectAnimator.REVERSE); 63 animator.setRepeatCount(ObjectAnimator.INFINITE); 64 animator.setDuration(4000); 65 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 66 @Override 67 public void onAnimationUpdate(ValueAnimator animation) { 68 ((View) mTextureView.getParent()).invalidate(); 69 } 70 }); 71 animator.start(); 72 } 73 74 @Override 75 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 76 } 77 78 @Override 79 public void onSurfaceTextureDestroyed(SurfaceTexture surface) { 80 mRenderThread.finish(); 81 try { 82 mRenderThread.join(); 83 } catch (InterruptedException e) { 84 Log.e(RenderThread.LOG_TAG, "Could not wait for render thread"); 85 } 86 } 87 88 @Override 89 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 90 } 91 92 private static class RenderThread extends Thread { 93 private static final String LOG_TAG = "GLTextureView"; 94 95 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 96 static final int EGL_OPENGL_ES2_BIT = 4; 97 98 private volatile boolean mFinished; 99 100 private SurfaceTexture mSurface; 101 102 private EGL10 mEgl; 103 private EGLDisplay mEglDisplay; 104 private EGLConfig mEglConfig; 105 private EGLContext mEglContext; 106 private EGLSurface mEglSurface; 107 private GL mGL; 108 109 RenderThread(SurfaceTexture surface) { 110 mSurface = surface; 111 } 112 113 @Override 114 public void run() { 115 initGL(); 116 117 float red = 1.0f; 118 while (!mFinished) { 119 checkCurrent(); 120 121 Log.d(LOG_TAG, "Rendering frame"); 122 123 GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f); 124 checkGlError(); 125 126 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 127 checkGlError(); 128 129 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 130 throw new RuntimeException("Cannot swap buffers"); 131 } 132 checkEglError(); 133 134 try { 135 Thread.sleep(20); 136 } catch (InterruptedException e) { 137 // Ignore 138 } 139 140 red += 0.021f; 141 if (red > 1.0f) red = 0.0f; 142 } 143 144 finishGL(); 145 } 146 147 private void checkEglError() { 148 int error = mEgl.eglGetError(); 149 if (error != EGL10.EGL_SUCCESS) { 150 Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error)); 151 } 152 } 153 154 private void checkGlError() { 155 int error = GLES20.glGetError(); 156 if (error != GLES20.GL_NO_ERROR) { 157 Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); 158 } 159 } 160 161 private void finishGL() { 162 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 163 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 164 } 165 166 private void checkCurrent() { 167 if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || 168 !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { 169 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 170 throw new RuntimeException("eglMakeCurrent failed " 171 + getEGLErrorString(mEgl.eglGetError())); 172 } 173 } 174 } 175 176 private void initGL() { 177 mEgl = (EGL10) EGLContext.getEGL(); 178 179 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 180 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 181 throw new RuntimeException("eglGetDisplay failed " 182 + getEGLErrorString(mEgl.eglGetError())); 183 } 184 185 int[] version = new int[2]; 186 if (!mEgl.eglInitialize(mEglDisplay, version)) { 187 throw new RuntimeException("eglInitialize failed " + 188 getEGLErrorString(mEgl.eglGetError())); 189 } 190 191 mEglConfig = chooseEglConfig(); 192 if (mEglConfig == null) { 193 throw new RuntimeException("eglConfig not initialized"); 194 } 195 196 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 197 198 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null); 199 200 if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 201 int error = mEgl.eglGetError(); 202 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 203 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 204 return; 205 } 206 throw new RuntimeException("createWindowSurface failed " 207 + getEGLErrorString(error)); 208 } 209 210 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 211 throw new RuntimeException("eglMakeCurrent failed " 212 + getEGLErrorString(mEgl.eglGetError())); 213 } 214 215 mGL = mEglContext.getGL(); 216 } 217 218 219 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 220 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 221 return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 222 } 223 224 private EGLConfig chooseEglConfig() { 225 int[] configsCount = new int[1]; 226 EGLConfig[] configs = new EGLConfig[1]; 227 int[] configSpec = getConfig(); 228 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 229 throw new IllegalArgumentException("eglChooseConfig failed " + 230 getEGLErrorString(mEgl.eglGetError())); 231 } else if (configsCount[0] > 0) { 232 return configs[0]; 233 } 234 return null; 235 } 236 237 private int[] getConfig() { 238 return new int[] { 239 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 240 EGL10.EGL_RED_SIZE, 8, 241 EGL10.EGL_GREEN_SIZE, 8, 242 EGL10.EGL_BLUE_SIZE, 8, 243 EGL10.EGL_ALPHA_SIZE, 8, 244 EGL10.EGL_DEPTH_SIZE, 0, 245 EGL10.EGL_STENCIL_SIZE, 0, 246 EGL10.EGL_NONE 247 }; 248 } 249 250 static String getEGLErrorString(int error) { 251 switch (error) { 252 case EGL10.EGL_SUCCESS: 253 return "EGL_SUCCESS"; 254 case EGL10.EGL_NOT_INITIALIZED: 255 return "EGL_NOT_INITIALIZED"; 256 case EGL10.EGL_BAD_ACCESS: 257 return "EGL_BAD_ACCESS"; 258 case EGL10.EGL_BAD_ALLOC: 259 return "EGL_BAD_ALLOC"; 260 case EGL10.EGL_BAD_ATTRIBUTE: 261 return "EGL_BAD_ATTRIBUTE"; 262 case EGL10.EGL_BAD_CONFIG: 263 return "EGL_BAD_CONFIG"; 264 case EGL10.EGL_BAD_CONTEXT: 265 return "EGL_BAD_CONTEXT"; 266 case EGL10.EGL_BAD_CURRENT_SURFACE: 267 return "EGL_BAD_CURRENT_SURFACE"; 268 case EGL10.EGL_BAD_DISPLAY: 269 return "EGL_BAD_DISPLAY"; 270 case EGL10.EGL_BAD_MATCH: 271 return "EGL_BAD_MATCH"; 272 case EGL10.EGL_BAD_NATIVE_PIXMAP: 273 return "EGL_BAD_NATIVE_PIXMAP"; 274 case EGL10.EGL_BAD_NATIVE_WINDOW: 275 return "EGL_BAD_NATIVE_WINDOW"; 276 case EGL10.EGL_BAD_PARAMETER: 277 return "EGL_BAD_PARAMETER"; 278 case EGL10.EGL_BAD_SURFACE: 279 return "EGL_BAD_SURFACE"; 280 case EGL11.EGL_CONTEXT_LOST: 281 return "EGL_CONTEXT_LOST"; 282 default: 283 return "0x" + Integer.toHexString(error); 284 } 285 } 286 287 void finish() { 288 mFinished = true; 289 } 290 } 291} 292