SurfaceFlinger now uses the new VSYNC HAL API.
If h/w composer doesn't support vsync (version < 0.3) we
"fake" it with a timer.
Change-Id: I1e3be79f43c9631d1293ad7d6cf52f9bfc42d65b
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 81e7359..60a6367 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -27,6 +27,10 @@
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
+extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
+ const struct timespec *request,
+ struct timespec *remain);
+
namespace android {
// ---------------------------------------------------------------------------
@@ -37,8 +41,15 @@
class HWComposer
{
public:
+ class EventHandler {
+ friend class HWComposer;
+ virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+ protected:
+ virtual ~EventHandler() {}
+ };
- HWComposer(const sp<SurfaceFlinger>& flinger);
+ HWComposer(const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler, nsecs_t refreshPeriod);
~HWComposer();
status_t initCheck() const;
@@ -46,7 +57,7 @@
// tells the HAL what the framebuffer is
void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
- // create a work list for numLayers layer
+ // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
status_t createWorkList(size_t numLayers);
// Asks the HAL what it can do
@@ -61,13 +72,86 @@
// release hardware resources
status_t release() const;
+ // get the layer array created by createWorkList()
size_t getNumLayers() const;
hwc_layer_t* getLayers() const;
- // updated in preapre()
+ // get number of layers of the given type as updated in prepare().
+ // type is HWC_OVERLAY or HWC_FRAMEBUFFER
size_t getLayerCount(int type) const;
- // for debugging
+ // Events handling ---------------------------------------------------------
+
+ enum {
+ EVENT_VSYNC = HWC_EVENT_VSYNC
+ };
+
+ status_t eventControl(int event, int enabled);
+
+ // this class is only used to fake the VSync event on systems that don't
+ // have it.
+ class VSyncThread : public Thread {
+ HWComposer& mHwc;
+ mutable Mutex mLock;
+ Condition mCondition;
+ bool mEnabled;
+ mutable nsecs_t mNextFakeVSync;
+ nsecs_t mRefreshPeriod;
+
+ virtual void onFirstRef() {
+ run("VSyncThread",
+ PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+ }
+
+ virtual bool threadLoop() {
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ while (!mEnabled) {
+ mCondition.wait(mLock);
+ }
+ }
+
+ const nsecs_t period = mRefreshPeriod;
+ const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ nsecs_t next_vsync = mNextFakeVSync;
+ nsecs_t sleep = next_vsync - now;
+ if (sleep < 0) {
+ // we missed, find where the next vsync should be
+ sleep = (period - ((now - next_vsync) % period));
+ next_vsync = now + sleep;
+ }
+ mNextFakeVSync = next_vsync + period;
+
+ struct timespec spec;
+ spec.tv_sec = next_vsync / 1000000000;
+ spec.tv_nsec = next_vsync % 1000000000;
+
+ // NOTE: EINTR can happen with clock_nanosleep(), in case of
+ // any error (including EINTR) we go through the condition's
+ // test -- this is always correct and easy.
+ if (::clock_nanosleep(CLOCK_MONOTONIC,
+ TIMER_ABSTIME, &spec, NULL) == 0) {
+ mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+ }
+ return true;
+ }
+
+ public:
+ VSyncThread(HWComposer& hwc) :
+ mHwc(hwc), mEnabled(false),
+ mNextFakeVSync(0),
+ mRefreshPeriod(hwc.mRefreshPeriod) {
+ }
+ void setEnabled(bool enabled) {
+ Mutex::Autolock _l(mLock);
+ mEnabled = enabled;
+ mCondition.signal();
+ }
+ };
+
+ friend class VSyncThread;
+
+ // for debugging ----------------------------------------------------------
void dump(String8& out, char* scratch, size_t SIZE,
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
@@ -88,8 +172,8 @@
static void hook_invalidate(struct hwc_procs* procs);
static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
- void invalidate();
- void vsync(int dpy, int64_t timestamp);
+ inline void invalidate();
+ inline void vsync(int dpy, int64_t timestamp);
sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
@@ -101,6 +185,9 @@
hwc_display_t mDpy;
hwc_surface_t mSur;
cb_context mCBContext;
+ EventHandler& mEventHandler;
+ nsecs_t mRefreshPeriod;
+ sp<VSyncThread> mVSyncThread;
};