diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f93db75c9..d2e01101f 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -10,7 +10,6 @@ LOCAL_SRC_FILES:= \ DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ DisplayHardware/HWComposer.cpp \ - DisplayHardware/VSyncBarrier.cpp \ GLExtensions.cpp \ MessageQueue.cpp \ SurfaceFlinger.cpp \ diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index b7584b36b..c46e630f4 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -35,6 +35,7 @@ #include +#include "DisplayHardwareBase.h" #include "GLExtensions.h" #include "HWComposer.h" #include "SurfaceFlinger.h" @@ -160,7 +161,6 @@ void DisplayHardware::init(uint32_t dpy) 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 @@ void DisplayHardware::init(uint32_t dpy) // 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& handler) { + Mutex::Autolock _l(mLock); + mVSyncHandler = handler; +} + +void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) { + sp 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 @@ uint32_t DisplayHardware::getPageFlipCount() const { 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 @@ nsecs_t DisplayHardware::getRefreshPeriod() const { 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 0a828b3dc..84a3effe7 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 @@ public: const sp& flinger, uint32_t displayIndex); - ~DisplayHardware(); + virtual ~DisplayHardware(); void releaseScreen() const; void acquireScreen() const; @@ -69,14 +78,15 @@ public: 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& handler); + uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } @@ -94,9 +104,9 @@ public: 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 mFlinger; EGLDisplay mDisplay; @@ -114,15 +124,18 @@ private: 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 mVSyncHandler; + sp mNativeWindow; }; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 94d002167..e742d3ee6 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -22,9 +22,11 @@ #include #include +#include #include #include +#include #include @@ -37,11 +39,16 @@ namespace android { // --------------------------------------------------------------------------- -HWComposer::HWComposer(const sp& flinger) +HWComposer::HWComposer( + const sp& 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 @@ HWComposer::HWComposer(const sp& flinger) 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::invalidate() { } 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 81e735998..60a636748 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -27,6 +27,10 @@ #include #include +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 LayerBase; class HWComposer { public: + class EventHandler { + friend class HWComposer; + virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0; + protected: + virtual ~EventHandler() {} + }; - HWComposer(const sp& flinger); + HWComposer(const sp& flinger, + EventHandler& handler, nsecs_t refreshPeriod); ~HWComposer(); status_t initCheck() const; @@ -46,7 +57,7 @@ public: // 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 @@ public: // 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 >& visibleLayersSortedByZ) const; @@ -88,8 +172,8 @@ private: 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 mFlinger; hw_module_t const* mModule; @@ -101,6 +185,9 @@ private: hwc_display_t mDpy; hwc_surface_t mSur; cb_context mCBContext; + EventHandler& mEventHandler; + nsecs_t mRefreshPeriod; + sp mVSyncThread; }; diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp b/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp deleted file mode 100644 index 187da203c..000000000 --- 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 -#include - -#include - -#include -#include -#include - -#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 3c3295050..000000000 --- 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 -#include - -#include -#include - -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_ */ diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 97afb5fa3..b05b7c281 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -38,13 +38,15 @@ namespace android { EventThread::EventThread(const sp& flinger) : mFlinger(flinger), - mHw(flinger->graphicPlane(0).displayHardware()), + mHw(flinger->graphicPlane(0).editDisplayHardware()), mLastVSyncTimestamp(0), + mVSyncTimestamp(0), mDeliveredEvents(0) { } void EventThread::onFirstRef() { + mHw.setVSyncHandler(this); run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); } @@ -105,76 +107,89 @@ void EventThread::requestNextVsync( } } +void EventThread::onVSyncReceived(int, nsecs_t timestamp) { + Mutex::Autolock _l(mLock); + mVSyncTimestamp = timestamp; + mCondition.signal(); +} + bool EventThread::threadLoop() { nsecs_t timestamp; DisplayEventReceiver::Event vsync; Vector< wp > displayEventConnections; - { // scope for the lock + do { + Mutex::Autolock _l(mLock); do { - // see if we need to wait for the VSYNC at all - do { - bool waitForNextVsync = false; - size_t count = mDisplayEventConnections.size(); - for (size_t i=0 ; i connection = - mDisplayEventConnections.itemAt(i).promote(); - if (connection!=0 && connection->count >= 0) { - // at least one continuous mode or active one-shot event - waitForNextVsync = true; - break; - } - } + // check if we have received a VSYNC event + if (mVSyncTimestamp) { + // we have a VSYNC event pending + timestamp = mVSyncTimestamp; + mVSyncTimestamp = 0; + break; + } - if (waitForNextVsync) - break; - - mCondition.wait(mLock); - } while(true); - - // at least one listener requested VSYNC - mLock.unlock(); - timestamp = mHw.waitForRefresh(); - ATRACE_INT("VSYNC", mDeliveredEvents&1); - mLock.lock(); - mDeliveredEvents++; - mLastVSyncTimestamp = timestamp; - - // now see if we still need to report this VSYNC event - const size_t count = mDisplayEventConnections.size(); + // check if we should be waiting for VSYNC events + bool waitForNextVsync = false; + size_t count = mDisplayEventConnections.size(); for (size_t i=0 ; i connection = mDisplayEventConnections.itemAt(i).promote(); - if (connection == 0) - continue; - - const int32_t count = connection->count; - if (count >= 1) { - if (count==1 || (mDeliveredEvents % count) == 0) { - // continuous event, and time to report it - reportVsync = true; - } - } else if (count >= -1) { - if (count == 0) { - // fired this time around - reportVsync = true; - } - connection->count--; - } - if (reportVsync) { - displayEventConnections.add(connection); + if (connection!=0 && connection->count >= 0) { + // at least one continuous mode or active one-shot event + waitForNextVsync = true; + break; } } - } while (!displayEventConnections.size()); - // dispatch vsync events to listeners... - vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; - vsync.header.timestamp = timestamp; - vsync.vsync.count = mDeliveredEvents; - } + // enable or disable VSYNC events + mHw.getHwComposer().eventControl( + HWComposer::EVENT_VSYNC, waitForNextVsync); + + // wait for something to happen + mCondition.wait(mLock); + } while(true); + + // process vsync event + + ATRACE_INT("VSYNC", mDeliveredEvents&1); + mDeliveredEvents++; + mLastVSyncTimestamp = timestamp; + + // now see if we still need to report this VSYNC event + const size_t count = mDisplayEventConnections.size(); + for (size_t i=0 ; i connection = + mDisplayEventConnections.itemAt(i).promote(); + if (connection == 0) + continue; + + const int32_t count = connection->count; + if (count >= 1) { + if (count==1 || (mDeliveredEvents % count) == 0) { + // continuous event, and time to report it + reportVsync = true; + } + } else if (count >= -1) { + if (count == 0) { + // fired this time around + reportVsync = true; + } + connection->count--; + } + if (reportVsync) { + displayEventConnections.add(connection); + } + } + } while (!displayEventConnections.size()); + + // dispatch vsync events to listeners... + vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + vsync.header.timestamp = timestamp; + vsync.vsync.count = mDeliveredEvents; const size_t count = displayEventConnections.size(); for (size_t i=0 ; i #include +#include "DisplayHardware/DisplayHardware.h" + // --------------------------------------------------------------------------- namespace android { @@ -34,11 +36,10 @@ namespace android { // --------------------------------------------------------------------------- class SurfaceFlinger; -class DisplayHardware; // --------------------------------------------------------------------------- -class EventThread : public Thread { +class EventThread : public Thread, public DisplayHardware::VSyncHandler { class Connection : public BnDisplayEventConnection { public: Connection(const sp& eventThread); @@ -80,12 +81,13 @@ private: virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); + virtual void onVSyncReceived(int, nsecs_t timestamp); void removeDisplayEventConnection(const wp& connection); // constants sp mFlinger; - const DisplayHardware& mHw; + DisplayHardware& mHw; mutable Mutex mLock; mutable Condition mCondition; @@ -93,6 +95,7 @@ private: // protected by mLock SortedVector< wp > mDisplayEventConnections; nsecs_t mLastVSyncTimestamp; + nsecs_t mVSyncTimestamp; // main thread only size_t mDeliveredEvents;