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