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