1 /*
2  * Copyright (C) 2009 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.testlatency;
18 
19 import android.content.Context;
20 import android.opengl.GLSurfaceView;
21 import android.util.AttributeSet;
22 import android.util.Log;
23 import android.view.KeyEvent;
24 import android.view.MotionEvent;
25 
26 import java.nio.ByteBuffer;
27 import java.nio.ByteOrder;
28 import java.nio.FloatBuffer;
29 
30 import javax.microedition.khronos.egl.EGL10;
31 import javax.microedition.khronos.egl.EGLConfig;
32 import javax.microedition.khronos.egl.EGLContext;
33 import javax.microedition.khronos.egl.EGLDisplay;
34 import javax.microedition.khronos.opengles.GL10;
35 
36 import android.opengl.GLES20;
37 
38 /**
39  * An implementation of SurfaceView that uses the dedicated surface for
40  * displaying an OpenGL animation.  This allows the animation to run in a
41  * separate thread, without requiring that it be driven by the update mechanism
42  * of the view hierarchy.
43  *
44  * The application-specific rendering code is delegated to a GLView.Renderer
45  * instance.
46  */
47 class TestLatencyView extends GLSurfaceView {
48     private static String TAG = "TestLatencyiew";
49     private float mX;
50     private float mY;
51     private float mDX;
52     private float mDY;
53     private long  mT;
54     private long  mDT;
55 
TestLatencyView(Context context)56     public TestLatencyView(Context context) {
57         super(context);
58         setEGLContextClientVersion(2);
59         setRenderer(new Renderer());
60     }
61 
62     @Override
onTouchEvent(MotionEvent event)63     public boolean onTouchEvent(MotionEvent event) {
64         switch (event.getAction()) {
65         case MotionEvent.ACTION_MOVE:
66             float x = event.getX();
67             float y = event.getY();
68             long  t = event.getEventTime();
69             synchronized(this) {
70                 mDT = t - mT;
71                 mT = t;
72                 mDX = x - mX;
73                 mX = x;
74                 mDY = y - mY;
75                 mY = y;
76             }
77             break;
78         default:
79             break;
80         }
81         return true;
82     }
83 
84     private class Renderer implements GLSurfaceView.Renderer {
85         private float mScaleX, mScaleY, mOffsetX, mOffsetY;
86         private final float MS_PER_FRAME = 1000 / 60;
Renderer()87         public Renderer() {
88             mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
89                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
90         }
91 
92 
onDrawFrame(GL10 gl)93         public void onDrawFrame(GL10 gl) {
94             GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
95             GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
96             GLES20.glUseProgram(mProgram);
97             checkGlError("glUseProgram");
98 
99             float x, y, dx, dy;
100             long t, dt;
101             synchronized(TestLatencyView.this) {
102                 x = mX;
103                 y = mY;
104                 dx = mDX;
105                 dy = mDY;
106                 dt = mDT;
107             }
108 
109             if (dt > 0) {
110                 dx = dx * MS_PER_FRAME / dt;
111                 dy = dy * MS_PER_FRAME / dt;
112             }
113 
114             GLES20.glEnableVertexAttribArray(mvPositionHandle);
115             checkGlError("glEnableVertexAttribArray");
116             GLES20.glEnableVertexAttribArray(mvColorHandle);
117             checkGlError("glEnableVertexAttribArray");
118             for(int step = 0; step < 8; step++) {
119                 float sx = (x + dx * step) * mScaleX + mOffsetX;
120                 float sy = (y + dy * step) * mScaleY + mOffsetY;
121                 int cbase = step * 4;
122 
123                 for (int i = 0; i < mTriangleVerticesData.length; i += 6) {
124                     mTriangleVerticesData2[i] = sx + mTriangleVerticesData[i];
125                     mTriangleVerticesData2[i+1] = -sy + mTriangleVerticesData[i+1];
126                     mTriangleVerticesData2[i+2] = mColors[cbase];
127                     mTriangleVerticesData2[i+3] = mColors[cbase+1];
128                     mTriangleVerticesData2[i+4] = mColors[cbase+2];
129                     mTriangleVerticesData2[i+5] = mColors[cbase+3];
130                 }
131                 mTriangleVertices.position(0);
132                 mTriangleVertices.put(mTriangleVerticesData2).position(0);
133 
134                 GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
135                 checkGlError("glVertexAttribPointer mvPosition");
136                 mTriangleVertices.put(mTriangleVerticesData2).position(2);
137                 GLES20.glVertexAttribPointer(mvColorHandle, 4, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices);
138                 checkGlError("glVertexAttribPointer mvColor");
139                 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
140                 checkGlError("glDrawArrays");
141             }
142         }
143 
onSurfaceChanged(GL10 gl, int width, int height)144         public void onSurfaceChanged(GL10 gl, int width, int height) {
145             GLES20.glViewport(0, 0, width, height);
146             mScaleX = 2.0f / width;
147             mScaleY = 2.0f / height;
148             mOffsetX = -1f;
149             mOffsetY = -1f;
150         }
151 
onSurfaceCreated(GL10 gl, EGLConfig config)152         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
153             mProgram = createProgram(mVertexShader, mFragmentShader);
154             if (mProgram == 0) {
155                 return;
156             }
157             mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
158             checkGlError("glGetAttribLocation");
159             if (mvPositionHandle == -1) {
160                 throw new RuntimeException("Could not get attrib location for vPosition");
161             }
162             mvColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
163             checkGlError("glGetAttribLocation");
164             if (mvColorHandle == -1) {
165                 throw new RuntimeException("Could not get attrib location for vColor");
166             }
167         }
168 
loadShader(int shaderType, String source)169         private int loadShader(int shaderType, String source) {
170             int shader = GLES20.glCreateShader(shaderType);
171             if (shader != 0) {
172                 GLES20.glShaderSource(shader, source);
173                 GLES20.glCompileShader(shader);
174                 int[] compiled = new int[1];
175                 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
176                 if (compiled[0] == 0) {
177                     Log.e(TAG, "Could not compile shader " + shaderType + ":");
178                     Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
179                     GLES20.glDeleteShader(shader);
180                     shader = 0;
181                 }
182             }
183             return shader;
184         }
185 
createProgram(String vertexSource, String fragmentSource)186         private int createProgram(String vertexSource, String fragmentSource) {
187             int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
188             if (vertexShader == 0) {
189                 return 0;
190             }
191 
192             int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
193             if (pixelShader == 0) {
194                 return 0;
195             }
196 
197             int program = GLES20.glCreateProgram();
198             if (program != 0) {
199                 GLES20.glAttachShader(program, vertexShader);
200                 checkGlError("glAttachShader vertexShader");
201                 GLES20.glAttachShader(program, pixelShader);
202                 checkGlError("glAttachShader pixelShader");
203                 GLES20.glLinkProgram(program);
204                 int[] linkStatus = new int[1];
205                 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
206                 if (linkStatus[0] != GLES20.GL_TRUE) {
207                     Log.e(TAG, "Could not link program: ");
208                     Log.e(TAG, GLES20.glGetProgramInfoLog(program));
209                     GLES20.glDeleteProgram(program);
210                     program = 0;
211                 }
212             }
213             return program;
214         }
215 
checkGlError(String op)216         private void checkGlError(String op) {
217             int error;
218             while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
219                 Log.e(TAG, op + ": glError " + error);
220                 throw new RuntimeException(op + ": glError " + error);
221             }
222         }
223 
224         // X, Y, R G B A
225         private final float[] mTriangleVerticesData = {
226                 -0.025f, 0.3f, 0.0f, 1.0f, 0.0f, 1.0f,
227                  0.0f  , 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
228                  0.025f, 0.3f, 1.0f, 1.0f, 255.0f, 1.0f
229                 };
230 
231         // Color cascade:
232         private final float[] mColors = {
233                 0.0f, 0.0f, 0.0f, 1.0f,
234                 0.5f, 0.0f, 0.0f, 1.0f,
235                 0.0f, 0.5f, 0.0f, 1.0f,
236                 0.5f, 0.5f, 0.0f, 1.0f,
237 
238                 0.0f, 0.0f, 0.5f, 1.0f,
239                 1.0f, 0.0f, 0.0f, 1.0f,
240                 1.0f, 1.0f, 1.0f, 1.0f,
241                 0.0f, 1.0f, 0.0f, 1.0f
242         };
243 
244         private float[] mTriangleVerticesData2 = new float[mTriangleVerticesData.length];
245         private FloatBuffer mTriangleVertices;
246 
247         private final String mVertexShader = "attribute vec4 aPosition;\n"
248             + "attribute vec4 aColor;\n"
249             + "varying vec4 vColor;\n"
250             + "void main() {\n"
251             + "  gl_Position = aPosition;\n"
252             + "  vColor = aColor;\n"
253             + "}\n";
254 
255         private final String mFragmentShader = "precision mediump float;\n"
256             + "varying vec4 vColor;\n"
257             + "void main() {\n"
258             + "  gl_FragColor = vColor;\n"
259             + "}\n";
260 
261         private int mProgram;
262         private int mvPositionHandle;
263         private int mvColorHandle;
264 
265     }
266 }
267 
268