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
17package com.android.testlatency;
18
19import android.content.Context;
20import android.opengl.GLSurfaceView;
21import android.util.AttributeSet;
22import android.util.Log;
23import android.view.KeyEvent;
24import android.view.MotionEvent;
25
26import java.nio.ByteBuffer;
27import java.nio.ByteOrder;
28import java.nio.FloatBuffer;
29
30import javax.microedition.khronos.egl.EGL10;
31import javax.microedition.khronos.egl.EGLConfig;
32import javax.microedition.khronos.egl.EGLContext;
33import javax.microedition.khronos.egl.EGLDisplay;
34import javax.microedition.khronos.opengles.GL10;
35
36import 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 */
47class 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
56    public TestLatencyView(Context context) {
57        super(context);
58        setEGLContextClientVersion(2);
59        setRenderer(new Renderer());
60    }
61
62    @Override
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;
87        public Renderer() {
88            mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
89                .order(ByteOrder.nativeOrder()).asFloatBuffer();
90        }
91
92
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
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
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
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
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
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