67ec1ad104
Avoid disabling DispSync resync if app and SF events aren't using phase offsets. This prevents hardware VSYNC from turning on always whenever something needs to be drawn, thereby bringing down the power numbers. Change-Id: I83c8f79eb46b9fdaa730ec32767ebed3286347b8
180 lines
6.7 KiB
C++
180 lines
6.7 KiB
C++
/*
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ANDROID_DISPSYNC_H
|
|
#define ANDROID_DISPSYNC_H
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <utils/Mutex.h>
|
|
#include <utils/Timers.h>
|
|
#include <utils/RefBase.h>
|
|
|
|
namespace android {
|
|
|
|
// Ignore present (retire) fences if the device doesn't have support for the
|
|
// sync framework.
|
|
#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK)
|
|
static const bool kIgnorePresentFences = true;
|
|
#else
|
|
static const bool kIgnorePresentFences = false;
|
|
#endif
|
|
|
|
|
|
class String8;
|
|
class Fence;
|
|
class DispSyncThread;
|
|
|
|
// DispSync maintains a model of the periodic hardware-based vsync events of a
|
|
// display and uses that model to execute period callbacks at specific phase
|
|
// offsets from the hardware vsync events. The model is constructed by
|
|
// feeding consecutive hardware event timestamps to the DispSync object via
|
|
// the addResyncSample method.
|
|
//
|
|
// The model is validated using timestamps from Fence objects that are passed
|
|
// to the DispSync object via the addPresentFence method. These fence
|
|
// timestamps should correspond to a hardware vsync event, but they need not
|
|
// be consecutive hardware vsync times. If this method determines that the
|
|
// current model accurately represents the hardware event times it will return
|
|
// false to indicate that a resynchronization (via addResyncSample) is not
|
|
// needed.
|
|
class DispSync {
|
|
|
|
public:
|
|
|
|
class Callback: public virtual RefBase {
|
|
public:
|
|
virtual ~Callback() {};
|
|
virtual void onDispSyncEvent(nsecs_t when) = 0;
|
|
};
|
|
|
|
DispSync();
|
|
~DispSync();
|
|
|
|
// reset clears the resync samples and error value.
|
|
void reset();
|
|
|
|
// addPresentFence adds a fence for use in validating the current vsync
|
|
// event model. The fence need not be signaled at the time
|
|
// addPresentFence is called. When the fence does signal, its timestamp
|
|
// should correspond to a hardware vsync event. Unlike the
|
|
// addResyncSample method, the timestamps of consecutive fences need not
|
|
// correspond to consecutive hardware vsync events.
|
|
//
|
|
// This method should be called with the retire fence from each HWComposer
|
|
// set call that affects the display.
|
|
bool addPresentFence(const sp<Fence>& fence);
|
|
|
|
// The beginResync, addResyncSample, and endResync methods are used to re-
|
|
// synchronize the DispSync's model to the hardware vsync events. The re-
|
|
// synchronization process involves first calling beginResync, then
|
|
// calling addResyncSample with a sequence of consecutive hardware vsync
|
|
// event timestamps, and finally calling endResync when addResyncSample
|
|
// indicates that no more samples are needed by returning false.
|
|
//
|
|
// This resynchronization process should be performed whenever the display
|
|
// is turned on (i.e. once immediately after it's turned on) and whenever
|
|
// addPresentFence returns true indicating that the model has drifted away
|
|
// from the hardware vsync events.
|
|
void beginResync();
|
|
bool addResyncSample(nsecs_t timestamp);
|
|
void endResync();
|
|
|
|
// The setPeriod method sets the vsync event model's period to a specific
|
|
// value. This should be used to prime the model when a display is first
|
|
// turned on. It should NOT be used after that.
|
|
void setPeriod(nsecs_t period);
|
|
|
|
// The getPeriod method returns the current vsync period.
|
|
nsecs_t getPeriod();
|
|
|
|
// setRefreshSkipCount specifies an additional number of refresh
|
|
// cycles to skip. For example, on a 60Hz display, a skip count of 1
|
|
// will result in events happening at 30Hz. Default is zero. The idea
|
|
// is to sacrifice smoothness for battery life.
|
|
void setRefreshSkipCount(int count);
|
|
|
|
// addEventListener registers a callback to be called repeatedly at the
|
|
// given phase offset from the hardware vsync events. The callback is
|
|
// called from a separate thread and it should return reasonably quickly
|
|
// (i.e. within a few hundred microseconds).
|
|
status_t addEventListener(nsecs_t phase, const sp<Callback>& callback);
|
|
|
|
// removeEventListener removes an already-registered event callback. Once
|
|
// this method returns that callback will no longer be called by the
|
|
// DispSync object.
|
|
status_t removeEventListener(const sp<Callback>& callback);
|
|
|
|
// computeNextRefresh computes when the next refresh is expected to begin.
|
|
// The periodOffset value can be used to move forward or backward; an
|
|
// offset of zero is the next refresh, -1 is the previous refresh, 1 is
|
|
// the refresh after next. etc.
|
|
nsecs_t computeNextRefresh(int periodOffset) const;
|
|
|
|
// dump appends human-readable debug info to the result string.
|
|
void dump(String8& result) const;
|
|
|
|
private:
|
|
|
|
void updateModelLocked();
|
|
void updateErrorLocked();
|
|
void resetErrorLocked();
|
|
|
|
enum { MAX_RESYNC_SAMPLES = 32 };
|
|
enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
|
|
enum { NUM_PRESENT_SAMPLES = 8 };
|
|
enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
|
|
|
|
// mPeriod is the computed period of the modeled vsync events in
|
|
// nanoseconds.
|
|
nsecs_t mPeriod;
|
|
|
|
// mPhase is the phase offset of the modeled vsync events. It is the
|
|
// number of nanoseconds from time 0 to the first vsync event.
|
|
nsecs_t mPhase;
|
|
|
|
// mError is the computed model error. It is based on the difference
|
|
// between the estimated vsync event times and those observed in the
|
|
// mPresentTimes array.
|
|
nsecs_t mError;
|
|
|
|
// These member variables are the state used during the resynchronization
|
|
// process to store information about the hardware vsync event times used
|
|
// to compute the model.
|
|
nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
|
|
size_t mFirstResyncSample;
|
|
size_t mNumResyncSamples;
|
|
int mNumResyncSamplesSincePresent;
|
|
|
|
// These member variables store information about the present fences used
|
|
// to validate the currently computed model.
|
|
sp<Fence> mPresentFences[NUM_PRESENT_SAMPLES];
|
|
nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
|
|
size_t mPresentSampleOffset;
|
|
|
|
int mRefreshSkipCount;
|
|
|
|
// mThread is the thread from which all the callbacks are called.
|
|
sp<DispSyncThread> mThread;
|
|
|
|
// mMutex is used to protect access to all member variables.
|
|
mutable Mutex mMutex;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // ANDROID_DISPSYNC_H
|