• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.view.cts;
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.os.Handler;
29 import android.os.HandlerThread;
30 import android.view.TextureView;
31 import android.view.TextureView.SurfaceTextureListener;
32 import android.view.View;
33 import android.view.ViewGroup.LayoutParams;
34 import android.widget.FrameLayout;
35 
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 
39 import javax.microedition.khronos.egl.EGL10;
40 import javax.microedition.khronos.egl.EGLConfig;
41 import javax.microedition.khronos.egl.EGLContext;
42 import javax.microedition.khronos.egl.EGLDisplay;
43 import javax.microedition.khronos.egl.EGLSurface;
44 
45 public class TextureViewCtsActivity extends Activity implements SurfaceTextureListener {
46     private final static long TIME_OUT_MS = 10000;
47     private Object mLock = new Object();
48 
49     private View mPreview;
50     private TextureView mTextureView;
51     private HandlerThread mGLThreadLooper;
52     private Handler mGLThread;
53 
54     private SurfaceTexture mSurface;
55     private int mSurfaceUpdatedCount;
56 
57     static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
58     static final int EGL_OPENGL_ES2_BIT = 4;
59 
60     private EGL10 mEgl;
61     private EGLDisplay mEglDisplay;
62     private EGLConfig mEglConfig;
63     private EGLContext mEglContext;
64     private EGLSurface mEglSurface;
65 
66     @Override
onCreate(Bundle savedInstanceState)67     protected void onCreate(Bundle savedInstanceState) {
68         super.onCreate(savedInstanceState);
69         if (mGLThreadLooper == null) {
70             mGLThreadLooper = new HandlerThread("GLThread");
71             mGLThreadLooper.start();
72             mGLThread = new Handler(mGLThreadLooper.getLooper());
73         }
74 
75         View preview = new View(this);
76         preview.setBackgroundColor(Color.WHITE);
77         mPreview = preview;
78         mTextureView = new TextureView(this);
79         mTextureView.setSurfaceTextureListener(this);
80 
81         FrameLayout content = new FrameLayout(this);
82         content.setBackgroundColor(Color.BLACK);
83         content.addView(mTextureView,
84                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
85         content.addView(mPreview,
86                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
87 
88         setContentView(content);
89     }
90 
91     private class RunSignalAndCatch implements Runnable {
92         public Throwable error;
93         private Runnable mRunnable;
94         private CountDownLatch mFence;
95 
RunSignalAndCatch(Runnable run, CountDownLatch fence)96         RunSignalAndCatch(Runnable run, CountDownLatch fence) {
97             mRunnable = run;
98             mFence = fence;
99         }
100 
101         @Override
run()102         public void run() {
103             try {
104                 mRunnable.run();
105             } catch (Throwable t) {
106                 error = t;
107             } finally {
108                 mFence.countDown();
109             }
110         }
111     }
112 
runOnGLThread(Runnable r)113     private void runOnGLThread(Runnable r) throws Throwable {
114         CountDownLatch fence = new CountDownLatch(1);
115         RunSignalAndCatch wrapper = new RunSignalAndCatch(r, fence);
116         mGLThread.post(wrapper);
117         fence.await(TIME_OUT_MS, TimeUnit.MILLISECONDS);
118         if (wrapper.error != null) {
119             throw wrapper.error;
120         }
121     }
122 
waitForSurface()123     public void waitForSurface() throws InterruptedException {
124         synchronized (mLock) {
125             while (mSurface == null) {
126                 mLock.wait(TIME_OUT_MS);
127             }
128         }
129     }
130 
initGl()131     public void initGl() throws Throwable {
132         if (mEglSurface != null) return;
133         runOnGLThread(mDoInitGL);
134     }
135 
drawColor(int color)136     public void drawColor(int color) throws Throwable {
137         runOnGLThread(() -> {
138             glClearColor(Color.red(color) / 255.0f,
139                     Color.green(color) / 255.0f,
140                     Color.blue(color) / 255.0f,
141                     Color.alpha(color) / 255.0f);
142             glClear(GL_COLOR_BUFFER_BIT);
143             if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
144                 throw new RuntimeException("Cannot swap buffers");
145             }
146         });
147     }
148 
finishGL()149     public void finishGL() throws Throwable {
150         if (mEglSurface == null) return;
151         runOnGLThread(() -> doFinishGL());
152     }
153 
waitForSurfaceUpdateCount(int updateCount)154     public int waitForSurfaceUpdateCount(int updateCount) throws InterruptedException {
155         synchronized (mLock) {
156             while (updateCount > mSurfaceUpdatedCount) {
157                 mLock.wait(TIME_OUT_MS);
158             }
159             return mSurfaceUpdatedCount;
160         }
161     }
162 
removeCover()163     public void removeCover() {
164         mPreview.setVisibility(View.GONE);
165     }
166 
doFinishGL()167     private void doFinishGL() {
168         mEgl.eglDestroyContext(mEglDisplay, mEglContext);
169         mEglContext = null;
170         mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
171         mEglSurface = null;
172         mEgl.eglTerminate(mEglDisplay);
173     }
174 
175     @Override
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)176     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
177         synchronized (mLock) {
178             mSurface = surface;
179             mLock.notifyAll();
180         }
181     }
182 
183     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)184     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
185     }
186 
187     @Override
onSurfaceTextureDestroyed(SurfaceTexture surface)188     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
189         synchronized (mLock) {
190             mSurface = null;
191             mLock.notifyAll();
192         }
193         return true;
194     }
195 
196     @Override
onSurfaceTextureUpdated(SurfaceTexture surface)197     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
198         synchronized (mLock) {
199             mSurfaceUpdatedCount++;
200             mLock.notifyAll();
201         }
202     }
203 
204     private Runnable mDoInitGL = new Runnable() {
205         @Override
206         public void run() {
207             mEgl = (EGL10) EGLContext.getEGL();
208 
209             mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
210             if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
211                 throw new RuntimeException("eglGetDisplay failed "
212                         + GLUtils.getEGLErrorString(mEgl.eglGetError()));
213             }
214 
215             int[] version = new int[2];
216             if (!mEgl.eglInitialize(mEglDisplay, version)) {
217                 throw new RuntimeException("eglInitialize failed " +
218                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
219             }
220 
221             mEglConfig = chooseEglConfig();
222             if (mEglConfig == null) {
223                 throw new RuntimeException("eglConfig not initialized");
224             }
225 
226             mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
227 
228             mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig,
229                     mSurface, null);
230 
231             if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
232                 int error = mEgl.eglGetError();
233                 throw new RuntimeException("createWindowSurface failed "
234                         + GLUtils.getEGLErrorString(error));
235             }
236 
237             if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
238                 throw new RuntimeException("eglMakeCurrent failed "
239                         + GLUtils.getEGLErrorString(mEgl.eglGetError()));
240             }
241         }
242     };
243 
createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig)244     EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
245         int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
246         return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
247     }
248 
chooseEglConfig()249     private EGLConfig chooseEglConfig() {
250         int[] configsCount = new int[1];
251         EGLConfig[] configs = new EGLConfig[1];
252         int[] configSpec = getConfig();
253         if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
254             throw new IllegalArgumentException("eglChooseConfig failed " +
255                     GLUtils.getEGLErrorString(mEgl.eglGetError()));
256         } else if (configsCount[0] > 0) {
257             return configs[0];
258         }
259         return null;
260     }
261 
getConfig()262     private int[] getConfig() {
263         return new int[] {
264                 EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
265                 EGL10.EGL_RED_SIZE, 8,
266                 EGL10.EGL_GREEN_SIZE, 8,
267                 EGL10.EGL_BLUE_SIZE, 8,
268                 EGL10.EGL_ALPHA_SIZE, 8,
269                 EGL10.EGL_DEPTH_SIZE, 0,
270                 EGL10.EGL_STENCIL_SIZE, 0,
271                 EGL10.EGL_NONE
272         };
273     }
274 }
275