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