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