1 /*
2  * Copyright (C) 2016 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.opengl.GLSurfaceView;
20 import android.util.Log;
21 import android.view.Window;
22 import android.view.WindowManager;
23 
24 import javax.microedition.khronos.egl.EGLConfig;
25 import javax.microedition.khronos.opengles.GL10;
26 
27 public class DisplayRefreshRateCtsActivity extends GLSurfaceViewCtsActivity {
28     private static final String TAG = "DisplayRefreshRateAct";
29 
30     public class FpsResult {
31         private float mFps;
32         private boolean mValid = false;
33         private boolean mRestartRequested = false;
34 
notifyResult(float fps)35         public final synchronized void notifyResult(float fps) {
36             if (!mValid) {
37                 mFps = fps;
38                 mValid = true;
39                 notifyAll();
40             }
41         }
42 
waitResult()43         public final synchronized float waitResult() {
44             while (!mValid) {
45                 try {
46                     wait();
47                 } catch (InterruptedException e) {/* ignore and retry */}
48             }
49             return mFps;
50         }
51 
restart()52         public synchronized void restart() {
53             mRestartRequested = true;
54             mValid = false;
55         }
restartNecessary()56         public synchronized boolean restartNecessary() {
57             return mRestartRequested;
58         }
ackRestart()59         public synchronized void ackRestart() {
60             mRestartRequested = false;
61         }
62     }
63 
64     private class Renderer implements GLSurfaceView.Renderer {
65         // Measurement knobs.
66         // NB: Some devices need a surprisingly long warmup period before the
67         // framerate becomes stable.
68         private static final float WARMUP_SECONDS = 2.0f;
69         private static final float TEST_SECONDS   = 8.0f;
70 
71         // Test states
72         private static final int STATE_START  = 0;
73         private static final int STATE_WARMUP = 1;
74         private static final int STATE_TEST   = 2;
75         private static final int STATE_DONE   = 3;
76 
77         private FpsResult mResult;
78         private int       mState     = STATE_START;
79         private float     mStartTime = 0.0f;
80         private int       mNumFrames = 0;
81 
Renderer(FpsResult result)82         public Renderer(FpsResult result) {
83             mResult = result;
84         }
85 
onDrawFrame(GL10 gl)86         public void onDrawFrame(GL10 gl) {
87             float t = (float)System.nanoTime() * 1.0e-9f;
88             switch (mState) {
89                 case STATE_START:
90                     mStartTime = t;
91                     mState = STATE_WARMUP;
92                     break;
93 
94                 case STATE_WARMUP:
95                     if ((t - mStartTime) >= WARMUP_SECONDS) {
96                         mStartTime = t;
97                         mNumFrames = 0;
98                         mState = STATE_TEST;
99                     }
100                     break;
101 
102                 case STATE_TEST:
103                     mNumFrames++;
104                     float elapsed = t - mStartTime;
105                     if (elapsed >= TEST_SECONDS) {
106                         mResult.notifyResult((float)mNumFrames / elapsed);
107                         mState = STATE_DONE;
108                     }
109                     break;
110 
111                 case STATE_DONE:
112                     if (mResult.restartNecessary()) {
113                         mResult.ackRestart();
114                         mState = STATE_START;
115                         Log.d(TAG, "restarting");
116                     }
117                     break;
118             }
119 
120             // prevent unwanted optimizations or hidden costs (e.g. reading
121             // previous frame on tilers).
122             gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
123             gl.glClear(gl.GL_COLOR_BUFFER_BIT);
124         }
125 
onSurfaceChanged(GL10 gl, int width, int height)126         public void onSurfaceChanged(GL10 gl, int width, int height) {
127             // Do nothing.
128         }
129 
onSurfaceCreated(GL10 gl, EGLConfig config)130         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
131             // Do nothing.
132         }
133     }
134 
135     private FpsResult mResult = new FpsResult();
136 
137     @Override
configureGLSurfaceView()138     protected void configureGLSurfaceView() {
139         mView.setRenderer(new Renderer(mResult));
140         mView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
141     }
142 
getFpsResult()143     public FpsResult getFpsResult() {
144         return mResult;
145     }
146 
setModeId(int modeId)147     public void setModeId(int modeId) {
148         runOnUiThread(() -> {
149             Window w = getWindow();
150             WindowManager.LayoutParams params = w.getAttributes();
151             params.preferredDisplayModeId = modeId;
152             w.setAttributes(params);
153         });
154 
155     }
156 }
157