mobile/android/base/gfx/DrawTimingQueue.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.gfx;
michael@0 7
michael@0 8 import android.os.SystemClock;
michael@0 9
michael@0 10 /**
michael@0 11 * A custom-built data structure to assist with measuring draw times.
michael@0 12 *
michael@0 13 * This class maintains a fixed-size circular buffer of DisplayPortMetrics
michael@0 14 * objects and associated timestamps. It provides only three operations, which
michael@0 15 * is all we require for our purposes of measuring draw times. Note
michael@0 16 * in particular that the class is designed so that even though it is
michael@0 17 * accessed from multiple threads, it does not require synchronization;
michael@0 18 * any concurrency errors that result from this are handled gracefully.
michael@0 19 *
michael@0 20 * Assuming an unrolled buffer so that mTail is greater than mHead, the data
michael@0 21 * stored in the buffer at entries [mHead, mTail) will never be modified, and
michael@0 22 * so are "safe" to read. If this reading is done on the same thread that
michael@0 23 * owns mHead, then reading the range [mHead, mTail) is guaranteed to be safe
michael@0 24 * since the range itself will not shrink.
michael@0 25 */
michael@0 26 final class DrawTimingQueue {
michael@0 27 private static final String LOGTAG = "GeckoDrawTimingQueue";
michael@0 28 private static final int BUFFER_SIZE = 16;
michael@0 29
michael@0 30 private final DisplayPortMetrics[] mMetrics;
michael@0 31 private final long[] mTimestamps;
michael@0 32
michael@0 33 private int mHead;
michael@0 34 private int mTail;
michael@0 35
michael@0 36 DrawTimingQueue() {
michael@0 37 mMetrics = new DisplayPortMetrics[BUFFER_SIZE];
michael@0 38 mTimestamps = new long[BUFFER_SIZE];
michael@0 39 mHead = BUFFER_SIZE - 1;
michael@0 40 mTail = 0;
michael@0 41 }
michael@0 42
michael@0 43 /**
michael@0 44 * Add a new entry to the tail of the queue. If the buffer is full,
michael@0 45 * do nothing. This must only be called from the Java UI thread.
michael@0 46 */
michael@0 47 boolean add(DisplayPortMetrics metrics) {
michael@0 48 if (mHead == mTail) {
michael@0 49 return false;
michael@0 50 }
michael@0 51 mMetrics[mTail] = metrics;
michael@0 52 mTimestamps[mTail] = SystemClock.uptimeMillis();
michael@0 53 mTail = (mTail + 1) % BUFFER_SIZE;
michael@0 54 return true;
michael@0 55 }
michael@0 56
michael@0 57 /**
michael@0 58 * Find the timestamp associated with the given metrics, AND remove
michael@0 59 * all metrics objects from the start of the queue up to and including
michael@0 60 * the one provided. Note that because of draw coalescing, the metrics
michael@0 61 * object passed in here may not be the one at the head of the queue,
michael@0 62 * and so we must iterate our way through the list to find it.
michael@0 63 * This must only be called from the compositor thread.
michael@0 64 */
michael@0 65 long findTimeFor(DisplayPortMetrics metrics) {
michael@0 66 // keep a copy of the tail pointer so that we ignore new items
michael@0 67 // added to the queue while we are searching. this is fine because
michael@0 68 // the one we are looking for will either have been added already
michael@0 69 // or will not be in the queue at all.
michael@0 70 int tail = mTail;
michael@0 71 // walk through the "safe" range from mHead to tail; these entries
michael@0 72 // will not be modified unless we change mHead.
michael@0 73 int i = (mHead + 1) % BUFFER_SIZE;
michael@0 74 while (i != tail) {
michael@0 75 if (mMetrics[i].fuzzyEquals(metrics)) {
michael@0 76 // found it, copy out the timestamp to a local var BEFORE
michael@0 77 // changing mHead or add could clobber the timestamp.
michael@0 78 long timestamp = mTimestamps[i];
michael@0 79 mHead = i;
michael@0 80 return timestamp;
michael@0 81 }
michael@0 82 i = (i + 1) % BUFFER_SIZE;
michael@0 83 }
michael@0 84 return -1;
michael@0 85 }
michael@0 86
michael@0 87 /**
michael@0 88 * Reset the buffer to empty.
michael@0 89 * This must only be called from the compositor thread.
michael@0 90 */
michael@0 91 void reset() {
michael@0 92 // we can only modify mHead on this thread.
michael@0 93 mHead = (mTail + BUFFER_SIZE - 1) % BUFFER_SIZE;
michael@0 94 }
michael@0 95 }

mercurial