1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.content.browser;
7 import android.content.Context;
8 import android.test.InstrumentationTestCase;
9 import android.test.suitebuilder.annotation.MediumTest;
10 import java.util.Arrays;
11 import java.util.concurrent.Callable;
13 import org.chromium.base.ThreadUtils;
15 public class VSyncMonitorTest extends InstrumentationTestCase {
16 private static class VSyncDataCollector implements VSyncMonitor.Listener {
17 public long mFramePeriods[];
18 public int mFrameCount;
20 private final boolean mActivelyRequestUpdate;
21 private boolean mDone;
22 private long mPreviousVSyncTimeMicros;
23 private Object mSyncRoot = new Object();
25 VSyncDataCollector(int frames, boolean activelyRequestUpdate) {
26 mFramePeriods = new long[frames];
27 mActivelyRequestUpdate = activelyRequestUpdate;
30 public boolean isDone() {
31 synchronized (mSyncRoot) {
37 public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
38 if (mPreviousVSyncTimeMicros == 0) {
39 mPreviousVSyncTimeMicros = vsyncTimeMicros;
42 if (mFrameCount >= mFramePeriods.length) {
43 synchronized (mSyncRoot) {
49 mFramePeriods[mFrameCount++] = vsyncTimeMicros - mPreviousVSyncTimeMicros;
50 mPreviousVSyncTimeMicros = vsyncTimeMicros;
51 if (mActivelyRequestUpdate) monitor.requestUpdate();
54 public void waitTillDone() throws InterruptedException {
55 synchronized (mSyncRoot) {
63 // The vsync monitor must be created on the UI thread to avoid associating the underlying
64 // Choreographer with the Looper from the test runner thread.
65 private VSyncMonitor createVSyncMonitor(
66 final VSyncMonitor.Listener listener, final boolean enableJBVSync) {
67 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<VSyncMonitor>() {
69 public VSyncMonitor call() {
70 Context context = getInstrumentation().getContext();
71 return new VSyncMonitor(context, listener, enableJBVSync);
76 // Check that the vsync period roughly matches the timestamps that the monitor generates.
77 private void performVSyncPeriodTest(boolean enableJBVSync) throws InterruptedException {
78 // Collect roughly one second of data on a 60 fps display.
79 collectAndCheckVSync(enableJBVSync, 60, true);
80 collectAndCheckVSync(enableJBVSync, VSyncMonitor.MAX_AUTO_ONVSYNC_COUNT, false);
83 private void collectAndCheckVSync(
84 boolean enableJBVSync, final int totalFrames, final boolean activeFrames)
85 throws InterruptedException {
86 VSyncDataCollector collector = new VSyncDataCollector(totalFrames, activeFrames);
87 VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync);
89 long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds();
90 assertTrue(reportedFramePeriod > 0);
92 assertFalse(collector.isDone());
93 monitor.requestUpdate();
94 collector.waitTillDone();
95 assertTrue(collector.isDone());
98 // Check that the median frame rate is within 10% of the reported frame period.
99 assertTrue(collector.mFrameCount == totalFrames);
100 Arrays.sort(collector.mFramePeriods, 0, collector.mFramePeriods.length);
101 long medianFramePeriod = collector.mFramePeriods[collector.mFramePeriods.length / 2];
102 if (Math.abs(medianFramePeriod - reportedFramePeriod) > reportedFramePeriod * .1) {
103 fail("Measured median frame period " + medianFramePeriod
104 + " differs by more than 10% from the reported frame period "
105 + reportedFramePeriod + " for "
106 + (activeFrames ? "requested" : "automatically sent") + " frames");
110 // Check that the vsync period roughly matches the timestamps that the monitor generates.
112 public void testVSyncPeriodAllowJBVSync() throws InterruptedException {
113 performVSyncPeriodTest(true);
116 // Check that the vsync period roughly matches the timestamps that the monitor generates.
118 public void testVSyncPeriodDisallowJBVSync() throws InterruptedException {
119 performVSyncPeriodTest(false);