1 /* 2 * Copyright (C) 2011 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 android.content.Context; 20 import android.opengl.GLSurfaceView; 21 import android.test.ActivityInstrumentationTestCase2; 22 import android.test.UiThreadTest; 23 import android.view.Display; 24 import android.view.WindowManager; 25 import android.util.Log; 26 27 import java.lang.InterruptedException; 28 import java.lang.Thread; 29 import java.util.ArrayList; 30 import javax.microedition.khronos.egl.EGLConfig; 31 import javax.microedition.khronos.opengles.GL10; 32 33 /** 34 * Test that the screen refresh rate claimed by 35 * android.view.Display.getRefreshRate() matches the steady-state framerate 36 * achieved by vsync-limited eglSwapBuffers(). The primary goal is to test 37 * Display.getRefreshRate() -- using GL is just an easy and hopefully reliable 38 * way of measuring the actual refresh rate. 39 */ 40 public class DisplayRefreshRateTest extends 41 ActivityInstrumentationTestCase2<GLSurfaceViewCtsActivity> { 42 43 // The test passes if 44 // abs(measured_fps - Display.getRefreshRate()) <= FPS_TOLERANCE. 45 // A smaller tolerance requires a more accurate measured_fps in order 46 // to avoid false negatives. 47 private static final float FPS_TOLERANCE = 2.0f; 48 49 private static final String TAG = "DisplayRefreshRateTest"; 50 51 private class FpsResult { 52 private float mFps; 53 private boolean mValid = false; 54 private boolean mRestartRequested = false; 55 notifyResult(float fps)56 public final synchronized void notifyResult(float fps) { 57 if (!mValid) { 58 mFps = fps; 59 mValid = true; 60 notifyAll(); 61 } 62 } 63 waitResult()64 public final synchronized float waitResult() { 65 while (!mValid) { 66 try { 67 wait(); 68 } catch (InterruptedException e) {/* ignore and retry */} 69 } 70 return mFps; 71 } 72 restart()73 public synchronized void restart() { 74 mRestartRequested = true; 75 mValid = false; 76 } restartNecessary()77 public synchronized boolean restartNecessary() { 78 return mRestartRequested; 79 } ackRestart()80 public synchronized void ackRestart() { 81 mRestartRequested = false; 82 } 83 } 84 85 private class Renderer implements GLSurfaceView.Renderer { 86 // Measurement knobs. 87 // NB: Some devices need a surprisingly long warmup period before the 88 // framerate becomes stable. 89 private static final float WARMUP_SECONDS = 2.0f; 90 private static final float TEST_SECONDS = 8.0f; 91 92 // Test states 93 private static final int STATE_START = 0; 94 private static final int STATE_WARMUP = 1; 95 private static final int STATE_TEST = 2; 96 private static final int STATE_DONE = 3; 97 98 private FpsResult mResult; 99 private int mState = STATE_START; 100 private float mStartTime = 0.0f; 101 private int mNumFrames = 0; 102 Renderer(FpsResult result)103 public Renderer(FpsResult result) { 104 mResult = result; 105 } 106 onDrawFrame(GL10 gl)107 public void onDrawFrame(GL10 gl) { 108 float t = (float)System.nanoTime() * 1.0e-9f; 109 switch (mState) { 110 case STATE_START: 111 mStartTime = t; 112 mState = STATE_WARMUP; 113 break; 114 115 case STATE_WARMUP: 116 if ((t - mStartTime) >= WARMUP_SECONDS) { 117 mStartTime = t; 118 mNumFrames = 0; 119 mState = STATE_TEST; 120 } 121 break; 122 123 case STATE_TEST: 124 mNumFrames++; 125 float elapsed = t - mStartTime; 126 if (elapsed >= TEST_SECONDS) { 127 mResult.notifyResult((float)mNumFrames / elapsed); 128 mState = STATE_DONE; 129 } 130 break; 131 132 case STATE_DONE: 133 if (mResult.restartNecessary()) { 134 mResult.ackRestart(); 135 mState = STATE_START; 136 Log.d(TAG, "restarting"); 137 } 138 break; 139 } 140 141 // prevent unwanted optimizations or hidden costs (e.g. reading 142 // previous frame on tilers). 143 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 144 gl.glClear(gl.GL_COLOR_BUFFER_BIT); 145 } 146 onSurfaceChanged(GL10 gl, int width, int height)147 public void onSurfaceChanged(GL10 gl, int width, int height) { 148 // Do nothing. 149 } 150 onSurfaceCreated(GL10 gl, EGLConfig config)151 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 152 // Do nothing. 153 } 154 } 155 156 private FpsResult mResult; 157 DisplayRefreshRateTest()158 public DisplayRefreshRateTest() { 159 super(GLSurfaceViewCtsActivity.class); 160 mResult = new FpsResult(); 161 } 162 163 @Override setUp()164 protected void setUp() throws Exception { 165 super.setUp(); 166 GLSurfaceViewCtsActivity.setRenderer(new Renderer(mResult)); 167 GLSurfaceViewCtsActivity.setRenderMode( 168 GLSurfaceView.RENDERMODE_CONTINUOUSLY); 169 } 170 testRefreshRate()171 public void testRefreshRate() throws java.lang.InterruptedException { 172 boolean fpsOk = false; 173 GLSurfaceViewCtsActivity activity = getActivity(); 174 175 WindowManager wm = (WindowManager)activity 176 .getView() 177 .getContext() 178 .getSystemService(Context.WINDOW_SERVICE); 179 Display dpy = wm.getDefaultDisplay(); 180 float claimedFps = dpy.getRefreshRate(); 181 182 for (int i = 0; i < 3; i++) { 183 float achievedFps = mResult.waitResult(); 184 Log.d(TAG, "claimed " + claimedFps + " fps, " + 185 "achieved " + achievedFps + " fps"); 186 fpsOk = Math.abs(claimedFps - achievedFps) <= FPS_TOLERANCE; 187 if (fpsOk) { 188 break; 189 } else { 190 // it could be other sctivity like bug report capturing for other failures 191 // sleep for a while and re-try 192 Thread.sleep(10000); 193 mResult.restart(); 194 } 195 } 196 activity.finish(); 197 assertTrue(fpsOk); 198 } 199 200 } 201