1 /*
2  * Copyright (C) 2016 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 
17 package com.android.test.hwui;
18 
19 import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
20 import static android.opengl.GLES20.glClear;
21 import static android.opengl.GLES20.glClearColor;
22 
23 import android.app.Activity;
24 import android.graphics.Color;
25 import android.graphics.SurfaceTexture;
26 import android.opengl.GLUtils;
27 import android.os.Bundle;
28 import android.util.Log;
29 import android.view.TextureView;
30 import android.view.TextureView.SurfaceTextureListener;
31 import android.view.View;
32 import android.view.ViewGroup.LayoutParams;
33 import android.widget.FrameLayout;
34 import android.widget.TextView;
35 
36 import javax.microedition.khronos.egl.EGL10;
37 import javax.microedition.khronos.egl.EGLConfig;
38 import javax.microedition.khronos.egl.EGLContext;
39 import javax.microedition.khronos.egl.EGLDisplay;
40 import javax.microedition.khronos.egl.EGLSurface;
41 
42 public class SingleFrameTextureViewTestActivity extends Activity implements SurfaceTextureListener {
43     private static final String LOG_TAG = "SingleFrameTest";
44 
45     private View mPreview;
46     private TextureView mTextureView;
47     private Thread mGLThread;
48 
49     @Override
onCreate(Bundle savedInstanceState)50     protected void onCreate(Bundle savedInstanceState) {
51         super.onCreate(savedInstanceState);
52         TextView preview = new TextView(this);
53         preview.setText("This is a preview");
54         preview.setBackgroundColor(Color.WHITE);
55         mPreview = preview;
56         mTextureView = new TextureView(this);
57         mTextureView.setSurfaceTextureListener(this);
58 
59         FrameLayout content = new FrameLayout(this);
60         content.addView(mTextureView,
61                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
62         content.addView(mPreview,
63                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
64 
65         setContentView(content);
66     }
67 
stopGlThread()68     private void stopGlThread() {
69         if (mGLThread != null) {
70             try {
71                 mGLThread.join();
72                 mGLThread = null;
73             } catch (InterruptedException e) { }
74         }
75     }
76 
77     @Override
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)78     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
79         Log.d(LOG_TAG, "onSurfaceAvailable");
80         mGLThread = new Thread() {
81             static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
82             static final int EGL_OPENGL_ES2_BIT = 4;
83 
84             private EGL10 mEgl;
85             private EGLDisplay mEglDisplay;
86             private EGLConfig mEglConfig;
87             private EGLContext mEglContext;
88             private EGLSurface mEglSurface;
89 
90             @Override
91             public void run() {
92                 initGL();
93                 try {
94                     Thread.sleep(500);
95                 } catch (InterruptedException e) {}
96 
97                 for (int i = 0; i < 2; i++) {
98                     if (i == 0) {
99                         glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
100                     } else {
101                         glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
102                     }
103                     glClear(GL_COLOR_BUFFER_BIT);
104                     Log.d(LOG_TAG, "eglSwapBuffers");
105                     if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
106                         throw new RuntimeException("Cannot swap buffers");
107                     }
108                     try {
109                         Thread.sleep(50);
110                     } catch (InterruptedException e) {}
111                 }
112 
113                 try {
114                     Thread.sleep(500);
115                 } catch (InterruptedException e) {}
116 
117                 finishGL();
118             }
119 
120             private void finishGL() {
121                 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
122                 mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
123             }
124 
125             private void initGL() {
126                 mEgl = (EGL10) EGLContext.getEGL();
127 
128                 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
129                 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
130                     throw new RuntimeException("eglGetDisplay failed "
131                             + GLUtils.getEGLErrorString(mEgl.eglGetError()));
132                 }
133 
134                 int[] version = new int[2];
135                 if (!mEgl.eglInitialize(mEglDisplay, version)) {
136                     throw new RuntimeException("eglInitialize failed " +
137                             GLUtils.getEGLErrorString(mEgl.eglGetError()));
138                 }
139 
140                 mEglConfig = chooseEglConfig();
141                 if (mEglConfig == null) {
142                     throw new RuntimeException("eglConfig not initialized");
143                 }
144 
145                 mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
146 
147                 mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
148 
149                 if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
150                     int error = mEgl.eglGetError();
151                     if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
152                         Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
153                         return;
154                     }
155                     throw new RuntimeException("createWindowSurface failed "
156                             + GLUtils.getEGLErrorString(error));
157                 }
158 
159                 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
160                     throw new RuntimeException("eglMakeCurrent failed "
161                             + GLUtils.getEGLErrorString(mEgl.eglGetError()));
162                 }
163             }
164 
165 
166             EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
167                 int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
168                 return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
169             }
170 
171             private EGLConfig chooseEglConfig() {
172                 int[] configsCount = new int[1];
173                 EGLConfig[] configs = new EGLConfig[1];
174                 int[] configSpec = getConfig();
175                 if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
176                     throw new IllegalArgumentException("eglChooseConfig failed " +
177                             GLUtils.getEGLErrorString(mEgl.eglGetError()));
178                 } else if (configsCount[0] > 0) {
179                     return configs[0];
180                 }
181                 return null;
182             }
183 
184             private int[] getConfig() {
185                 return new int[] {
186                         EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
187                         EGL10.EGL_RED_SIZE, 8,
188                         EGL10.EGL_GREEN_SIZE, 8,
189                         EGL10.EGL_BLUE_SIZE, 8,
190                         EGL10.EGL_ALPHA_SIZE, 8,
191                         EGL10.EGL_DEPTH_SIZE, 0,
192                         EGL10.EGL_STENCIL_SIZE, 0,
193                         EGL10.EGL_NONE
194                 };
195             }
196         };
197         mGLThread.start();
198     }
199 
200     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)201     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
202         Log.d(LOG_TAG, "onSurfaceTextureSizeChanged");
203     }
204 
205     @Override
onSurfaceTextureDestroyed(SurfaceTexture surface)206     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
207         Log.d(LOG_TAG, "onSurfaceTextureDestroyed");
208         stopGlThread();
209         return true;
210     }
211 
212     @Override
onSurfaceTextureUpdated(SurfaceTexture surface)213     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
214         Log.d(LOG_TAG, "onSurfaceTextureUpdated");
215         mPreview.setVisibility(View.GONE);
216     }
217 }
218