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/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index b7584b3..c46e630 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -35,6 +35,7 @@
#include <hardware/gralloc.h>
+#include "DisplayHardwareBase.h"
#include "GLExtensions.h"
#include "HWComposer.h"
#include "SurfaceFlinger.h"
@@ -160,7 +161,6 @@
mDpiX = mNativeWindow->xdpi;
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
- mNextFakeVSync = 0;
if (mDpiX == 0 || mDpiY == 0) {
ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), "
@@ -353,12 +353,32 @@
// initialize the H/W composer
- mHwc = new HWComposer(mFlinger);
+ mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
}
+void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
+ Mutex::Autolock _l(mLock);
+ mVSyncHandler = handler;
+}
+
+void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {
+ sp<VSyncHandler> handler;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ mLastHwVSync = timestamp;
+ if (mVSyncHandler != NULL) {
+ handler = mVSyncHandler.promote();
+ }
+ }
+
+ if (handler != NULL) {
+ handler->onVSyncReceived(dpy, timestamp);
+ }
+}
+
HWComposer& DisplayHardware::getHwComposer() const {
return *mHwc;
}
@@ -393,22 +413,12 @@
return mPageFlipCount;
}
-// this needs to be thread safe
-nsecs_t DisplayHardware::waitForRefresh() const {
- nsecs_t timestamp;
- if (mVSync.wait(×tamp) < 0) {
- // vsync not supported!
- usleep( getDelayToNextVSyncUs(×tamp) );
- }
- mLastHwVSync = timestamp; // FIXME: Not thread safe
- return timestamp;
-}
-
nsecs_t DisplayHardware::getRefreshTimestamp() const {
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
- nsecs_t now = systemTime();
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime(CLOCK_MONOTONIC);
return now - ((now - mLastHwVSync) % mRefreshPeriod);
}
@@ -416,27 +426,6 @@
return mRefreshPeriod;
}
-int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const {
- Mutex::Autolock _l(mFakeVSyncMutex);
- 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;
- timestamp[0] = next_vsync;
-
- // round to next microsecond
- int32_t sleep_us = (sleep + 999LL) / 1000LL;
-
- // guaranteed to be > 0
- return sleep_us;
-}
-
status_t DisplayHardware::compositionComplete() const {
return mNativeWindow->compositionComplete();
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 0a828b3..84a3eff 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -30,16 +30,25 @@
#include "GLExtensions.h"
#include "DisplayHardware/DisplayHardwareBase.h"
-#include "DisplayHardware/VSyncBarrier.h"
+#include "HWComposer.h"
namespace android {
class FramebufferNativeWindow;
-class HWComposer;
-class DisplayHardware : public DisplayHardwareBase
+class DisplayHardware :
+ public DisplayHardwareBase,
+ public HWComposer::EventHandler
{
public:
+
+ class VSyncHandler : virtual public RefBase {
+ friend class DisplayHardware;
+ virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+ protected:
+ virtual ~VSyncHandler() {}
+ };
+
enum {
COPY_BITS_EXTENSION = 0x00000008,
BUFFER_PRESERVED = 0x00010000,
@@ -52,7 +61,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex);
- ~DisplayHardware();
+ virtual ~DisplayHardware();
void releaseScreen() const;
void acquireScreen() const;
@@ -69,14 +78,15 @@
int getHeight() const;
PixelFormat getFormat() const;
uint32_t getFlags() const;
- void makeCurrent() const;
uint32_t getMaxTextureSize() const;
uint32_t getMaxViewportDims() const;
-
- // waits for the next vsync and returns the timestamp of when it happened
- nsecs_t waitForRefresh() const;
nsecs_t getRefreshPeriod() const;
nsecs_t getRefreshTimestamp() const;
+ void makeCurrent() const;
+
+
+ void setVSyncHandler(const sp<VSyncHandler>& handler);
+
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -94,9 +104,9 @@
inline Rect bounds() const { return getBounds(); }
private:
+ virtual void onVSyncReceived(int dpy, nsecs_t timestamp);
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
- int32_t getDelayToNextVSyncUs(nsecs_t* timestamp) const;
sp<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
@@ -114,15 +124,18 @@
mutable uint32_t mPageFlipCount;
GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
- VSyncBarrier mVSync;
- mutable Mutex mFakeVSyncMutex;
- mutable nsecs_t mNextFakeVSync;
nsecs_t mRefreshPeriod;
mutable nsecs_t mLastHwVSync;
+ // constant once set
HWComposer* mHwc;
+ mutable Mutex mLock;
+
+ // protected by mLock
+ wp<VSyncHandler> mVSyncHandler;
+
sp<FramebufferNativeWindow> mNativeWindow;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 94d0021..e742d3e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -22,9 +22,11 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/Thread.h>
#include <utils/Vector.h>
#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
#include <cutils/log.h>
@@ -37,11 +39,16 @@
namespace android {
// ---------------------------------------------------------------------------
-HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+HWComposer::HWComposer(
+ const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler,
+ nsecs_t refreshPeriod)
: mFlinger(flinger),
mModule(0), mHwc(0), mList(0), mCapacity(0),
mNumOVLayers(0), mNumFBLayers(0),
- mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+ mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE),
+ mEventHandler(handler),
+ mRefreshPeriod(refreshPeriod)
{
int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
@@ -57,12 +64,20 @@
mHwc->registerProcs(mHwc, &mCBContext.procs);
memset(mCBContext.procs.zero, 0, sizeof(mCBContext.procs.zero));
}
+
+ if (mHwc->common.version < HWC_DEVICE_API_VERSION_0_3) {
+ // we don't have VSYNC support, we need to fake it
+ mVSyncThread = new VSyncThread(*this);
+ }
}
}
}
HWComposer::~HWComposer() {
free(mList);
+ if (mVSyncThread != NULL) {
+ mVSyncThread->requestExitAndWait();
+ }
if (mHwc) {
hwc_close(mHwc);
}
@@ -85,6 +100,21 @@
}
void HWComposer::vsync(int dpy, int64_t timestamp) {
+ mEventHandler.onVSyncReceived(dpy, timestamp);
+}
+
+status_t HWComposer::eventControl(int event, int enabled) {
+ status_t err = NO_ERROR;
+ if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+ err = mHwc->methods->eventControl(mHwc, event, enabled);
+ } else {
+ if (mVSyncThread != NULL) {
+ mVSyncThread->setEnabled(enabled);
+ } else {
+ err = BAD_VALUE;
+ }
+ }
+ return err;
}
void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
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;
};
diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp b/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp
deleted file mode 100644
index 187da20..0000000
--- a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-
-#include "DisplayHardware/VSyncBarrier.h"
-
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-VSyncBarrier::VSyncBarrier() : mFd(-EINVAL) {
-#if HAS_WAITFORVSYNC
- mFd = open("/dev/graphics/fb0", O_RDWR);
- if (mFd < 0) {
- mFd = -errno;
- }
- // try to see if FBIO_WAITFORVSYNC is supported
- uint32_t crt = 0;
- int err = ioctl(mFd, FBIO_WAITFORVSYNC, &crt);
- if (err < 0) {
- close(mFd);
- mFd = -EINVAL;
- }
-#endif
-}
-
-VSyncBarrier::~VSyncBarrier() {
- if (mFd >= 0) {
- close(mFd);
- }
-}
-
-status_t VSyncBarrier::initCheck() const {
- return mFd < 0 ? mFd : status_t(NO_ERROR);
-}
-
-// this must be thread-safe
-status_t VSyncBarrier::wait(nsecs_t* timestamp) const {
- if (mFd < 0) {
- return mFd;
- }
-
- int err;
- uint32_t crt = 0;
- do {
- err = ioctl(mFd, FBIO_WAITFORVSYNC, &crt);
- } while (err<0 && errno==EINTR);
- if (err < 0) {
- return -errno;
- }
- // ideally this would come from the driver
- timestamp[0] = systemTime();
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.h b/services/surfaceflinger/DisplayHardware/VSyncBarrier.h
deleted file mode 100644
index 3c32950..0000000
--- a/services/surfaceflinger/DisplayHardware/VSyncBarrier.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2011 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_SURFACE_FLINGER_VSYNCBARRIER_H_
-#define ANDROID_SURFACE_FLINGER_VSYNCBARRIER_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class VSyncBarrier {
- int mFd;
-public:
- VSyncBarrier();
- ~VSyncBarrier();
- status_t initCheck() const;
- status_t wait(nsecs_t* timestamp) const;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* ANDROID_SURFACE_FLINGER_VSYNCBARRIER_H_ */