GLTextureViewActivity.java revision 451ce44a18e4c48f8a43aa250957f76967a35d31
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 private static class RenderThread extends Thread { 89 private static final String LOG_TAG = "GLTextureView"; 90 91 static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 92 static final int EGL_SURFACE_TYPE = 0x3033; 93 static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400; 94 static final int EGL_OPENGL_ES2_BIT = 4; 95 96 private volatile boolean mFinished; 97 98 private SurfaceTexture mSurface; 99 100 private EGL10 mEgl; 101 private EGLDisplay mEglDisplay; 102 private EGLConfig mEglConfig; 103 private EGLContext mEglContext; 104 private EGLSurface mEglSurface; 105 private GL mGL; 106 107 RenderThread(SurfaceTexture surface) { 108 mSurface = surface; 109 } 110 111 @Override 112 public void run() { 113 initGL(); 114 115 float red = 1.0f; 116 while (!mFinished) { 117 checkCurrent(); 118 119 Log.d(LOG_TAG, "Rendering frame"); 120 121 GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f); 122 checkGlError(); 123 124 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 125 checkGlError(); 126 127 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { 128 throw new RuntimeException("Cannot swap buffers"); 129 } 130 checkEglError(); 131 132 try { 133 Thread.sleep(20); 134 } catch (InterruptedException e) { 135 // Ignore 136 } 137 138 red += 0.021f; 139 if (red > 1.0f) red = 0.0f; 140 } 141 142 finishGL(); 143 } 144 145 private void checkEglError() { 146 int error = mEgl.eglGetError(); 147 if (error != EGL10.EGL_SUCCESS) { 148 Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error)); 149 } 150 } 151 152 private void checkGlError() { 153 int error = GLES20.glGetError(); 154 if (error != GLES20.GL_NO_ERROR) { 155 Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error)); 156 } 157 } 158 159 private void finishGL() { 160 mEgl.eglDestroyContext(mEglDisplay, mEglContext); 161 mEgl.eglDestroySurface(mEglDisplay, mEglSurface); 162 } 163 164 private void checkCurrent() { 165 if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || 166 !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { 167 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 168 throw new RuntimeException("eglMakeCurrent failed " 169 + getEGLErrorString(mEgl.eglGetError())); 170 } 171 } 172 } 173 174 private void initGL() { 175 mEgl = (EGL10) EGLContext.getEGL(); 176 177 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 178 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { 179 throw new RuntimeException("eglGetDisplay failed " 180 + getEGLErrorString(mEgl.eglGetError())); 181 } 182 183 int[] version = new int[2]; 184 if (!mEgl.eglInitialize(mEglDisplay, version)) { 185 throw new RuntimeException("eglInitialize failed " + 186 getEGLErrorString(mEgl.eglGetError())); 187 } 188 189 mEglConfig = chooseEglConfig(); 190 if (mEglConfig == null) { 191 throw new RuntimeException("eglConfig not initialized"); 192 } 193 194 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); 195 196 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null); 197 198 if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { 199 int error = mEgl.eglGetError(); 200 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { 201 Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); 202 return; 203 } 204 throw new RuntimeException("createWindowSurface failed " 205 + getEGLErrorString(error)); 206 } 207 208 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 209 throw new RuntimeException("eglMakeCurrent failed " 210 + getEGLErrorString(mEgl.eglGetError())); 211 } 212 213 mGL = mEglContext.getGL(); 214 } 215 216 217 EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) { 218 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 219 return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 220 } 221 222 private EGLConfig chooseEglConfig() { 223 int[] configsCount = new int[1]; 224 EGLConfig[] configs = new EGLConfig[1]; 225 int[] configSpec = getConfig(); 226 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) { 227 throw new IllegalArgumentException("eglChooseConfig failed " + 228 getEGLErrorString(mEgl.eglGetError())); 229 } else if (configsCount[0] > 0) { 230 return configs[0]; 231 } 232 return null; 233 } 234 235 private int[] getConfig() { 236 return new int[] { 237 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 238 EGL10.EGL_RED_SIZE, 8, 239 EGL10.EGL_GREEN_SIZE, 8, 240 EGL10.EGL_BLUE_SIZE, 8, 241 EGL10.EGL_ALPHA_SIZE, 8, 242 EGL10.EGL_DEPTH_SIZE, 0, 243 EGL10.EGL_STENCIL_SIZE, 0, 244 EGL10.EGL_NONE 245 }; 246 } 247 248 static String getEGLErrorString(int error) { 249 switch (error) { 250 case EGL10.EGL_SUCCESS: 251 return "EGL_SUCCESS"; 252 case EGL10.EGL_NOT_INITIALIZED: 253 return "EGL_NOT_INITIALIZED"; 254 case EGL10.EGL_BAD_ACCESS: 255 return "EGL_BAD_ACCESS"; 256 case EGL10.EGL_BAD_ALLOC: 257 return "EGL_BAD_ALLOC"; 258 case EGL10.EGL_BAD_ATTRIBUTE: 259 return "EGL_BAD_ATTRIBUTE"; 260 case EGL10.EGL_BAD_CONFIG: 261 return "EGL_BAD_CONFIG"; 262 case EGL10.EGL_BAD_CONTEXT: 263 return "EGL_BAD_CONTEXT"; 264 case EGL10.EGL_BAD_CURRENT_SURFACE: 265 return "EGL_BAD_CURRENT_SURFACE"; 266 case EGL10.EGL_BAD_DISPLAY: 267 return "EGL_BAD_DISPLAY"; 268 case EGL10.EGL_BAD_MATCH: 269 return "EGL_BAD_MATCH"; 270 case EGL10.EGL_BAD_NATIVE_PIXMAP: 271 return "EGL_BAD_NATIVE_PIXMAP"; 272 case EGL10.EGL_BAD_NATIVE_WINDOW: 273 return "EGL_BAD_NATIVE_WINDOW"; 274 case EGL10.EGL_BAD_PARAMETER: 275 return "EGL_BAD_PARAMETER"; 276 case EGL10.EGL_BAD_SURFACE: 277 return "EGL_BAD_SURFACE"; 278 case EGL11.EGL_CONTEXT_LOST: 279 return "EGL_CONTEXT_LOST"; 280 default: 281 return "0x" + Integer.toHexString(error); 282 } 283 } 284 285 void finish() { 286 mFinished = true; 287 } 288 } 289} 290