mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
96 lines
3.7 KiB
Java
96 lines
3.7 KiB
Java
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
|
||
|
package org.mozilla.gecko.gfx;
|
||
|
|
||
|
import android.os.SystemClock;
|
||
|
|
||
|
/**
|
||
|
* A custom-built data structure to assist with measuring draw times.
|
||
|
*
|
||
|
* This class maintains a fixed-size circular buffer of DisplayPortMetrics
|
||
|
* objects and associated timestamps. It provides only three operations, which
|
||
|
* is all we require for our purposes of measuring draw times. Note
|
||
|
* in particular that the class is designed so that even though it is
|
||
|
* accessed from multiple threads, it does not require synchronization;
|
||
|
* any concurrency errors that result from this are handled gracefully.
|
||
|
*
|
||
|
* Assuming an unrolled buffer so that mTail is greater than mHead, the data
|
||
|
* stored in the buffer at entries [mHead, mTail) will never be modified, and
|
||
|
* so are "safe" to read. If this reading is done on the same thread that
|
||
|
* owns mHead, then reading the range [mHead, mTail) is guaranteed to be safe
|
||
|
* since the range itself will not shrink.
|
||
|
*/
|
||
|
final class DrawTimingQueue {
|
||
|
private static final String LOGTAG = "GeckoDrawTimingQueue";
|
||
|
private static final int BUFFER_SIZE = 16;
|
||
|
|
||
|
private final DisplayPortMetrics[] mMetrics;
|
||
|
private final long[] mTimestamps;
|
||
|
|
||
|
private int mHead;
|
||
|
private int mTail;
|
||
|
|
||
|
DrawTimingQueue() {
|
||
|
mMetrics = new DisplayPortMetrics[BUFFER_SIZE];
|
||
|
mTimestamps = new long[BUFFER_SIZE];
|
||
|
mHead = BUFFER_SIZE - 1;
|
||
|
mTail = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a new entry to the tail of the queue. If the buffer is full,
|
||
|
* do nothing. This must only be called from the Java UI thread.
|
||
|
*/
|
||
|
boolean add(DisplayPortMetrics metrics) {
|
||
|
if (mHead == mTail) {
|
||
|
return false;
|
||
|
}
|
||
|
mMetrics[mTail] = metrics;
|
||
|
mTimestamps[mTail] = SystemClock.uptimeMillis();
|
||
|
mTail = (mTail + 1) % BUFFER_SIZE;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Find the timestamp associated with the given metrics, AND remove
|
||
|
* all metrics objects from the start of the queue up to and including
|
||
|
* the one provided. Note that because of draw coalescing, the metrics
|
||
|
* object passed in here may not be the one at the head of the queue,
|
||
|
* and so we must iterate our way through the list to find it.
|
||
|
* This must only be called from the compositor thread.
|
||
|
*/
|
||
|
long findTimeFor(DisplayPortMetrics metrics) {
|
||
|
// keep a copy of the tail pointer so that we ignore new items
|
||
|
// added to the queue while we are searching. this is fine because
|
||
|
// the one we are looking for will either have been added already
|
||
|
// or will not be in the queue at all.
|
||
|
int tail = mTail;
|
||
|
// walk through the "safe" range from mHead to tail; these entries
|
||
|
// will not be modified unless we change mHead.
|
||
|
int i = (mHead + 1) % BUFFER_SIZE;
|
||
|
while (i != tail) {
|
||
|
if (mMetrics[i].fuzzyEquals(metrics)) {
|
||
|
// found it, copy out the timestamp to a local var BEFORE
|
||
|
// changing mHead or add could clobber the timestamp.
|
||
|
long timestamp = mTimestamps[i];
|
||
|
mHead = i;
|
||
|
return timestamp;
|
||
|
}
|
||
|
i = (i + 1) % BUFFER_SIZE;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reset the buffer to empty.
|
||
|
* This must only be called from the compositor thread.
|
||
|
*/
|
||
|
void reset() {
|
||
|
// we can only modify mHead on this thread.
|
||
|
mHead = (mTail + BUFFER_SIZE - 1) % BUFFER_SIZE;
|
||
|
}
|
||
|
}
|