diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/surfaceflinger/Android.mk | 27 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/DisplayHardware.cpp | 34 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/DisplayHardware.h | 12 | ||||
-rw-r--r-- | services/surfaceflinger/MessageQueue.cpp | 186 | ||||
-rw-r--r-- | services/surfaceflinger/MessageQueue.h | 79 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 71 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 8 |
7 files changed, 174 insertions, 243 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f63c0c1..95d651a 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -2,19 +2,22 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - Layer.cpp \ - LayerBase.cpp \ - LayerDim.cpp \ - LayerScreenshot.cpp \ - DdmConnection.cpp \ - DisplayHardware/DisplayHardware.cpp \ + EventThread.cpp \ + Layer.cpp \ + LayerBase.cpp \ + LayerDim.cpp \ + LayerScreenshot.cpp \ + DdmConnection.cpp \ + DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ - DisplayHardware/HWComposer.cpp \ - GLExtensions.cpp \ - MessageQueue.cpp \ - SurfaceFlinger.cpp \ - SurfaceTextureLayer.cpp \ - Transform.cpp \ + DisplayHardware/HWComposer.cpp \ + DisplayHardware/VSyncBarrier.cpp \ + DisplayEventConnection.cpp \ + GLExtensions.cpp \ + MessageQueue.cpp \ + SurfaceFlinger.cpp \ + SurfaceTextureLayer.cpp \ + Transform.cpp \ LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index f94d321..3bbc75e 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -140,6 +140,7 @@ void DisplayHardware::init(uint32_t dpy) mDpiX = mNativeWindow->xdpi; mDpiY = mNativeWindow->ydpi; mRefreshRate = fbDev->fps; + mNextFakeVSync = 0; /* FIXME: this is a temporary HACK until we are able to report the refresh rate @@ -152,6 +153,8 @@ void DisplayHardware::init(uint32_t dpy) #warning "refresh rate set via makefile to REFRESH_RATE" #endif + mRefreshPeriod = nsecs_t(1e9 / mRefreshRate); + EGLint w, h, dummy; EGLint numConfigs=0; EGLSurface surface; @@ -346,6 +349,37 @@ uint32_t DisplayHardware::getPageFlipCount() const { return mPageFlipCount; } +// this needs to be thread safe +nsecs_t DisplayHardware::waitForVSync() const { + nsecs_t timestamp; + if (mVSync.wait(×tamp) < 0) { + // vsync not supported! + usleep( getDelayToNextVSyncUs(×tamp) ); + } + return timestamp; +} + +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 f02c954..45d4b45 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -32,6 +32,7 @@ #include "GLExtensions.h" #include "DisplayHardware/DisplayHardwareBase.h" +#include "DisplayHardware/VSyncBarrier.h" namespace android { @@ -74,6 +75,9 @@ public: uint32_t getMaxTextureSize() const; uint32_t getMaxViewportDims() const; + // waits for the next vsync and returns the timestamp of when it happened + nsecs_t waitForVSync() const; + uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } @@ -95,6 +99,7 @@ public: private: void init(uint32_t displayIndex) __attribute__((noinline)); void fini() __attribute__((noinline)); + int32_t getDelayToNextVSyncUs(nsecs_t* timestamp) const; sp<SurfaceFlinger> mFlinger; EGLDisplay mDisplay; @@ -112,7 +117,12 @@ private: mutable uint32_t mPageFlipCount; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; - + VSyncBarrier mVSync; + + mutable Mutex mFakeVSyncMutex; + mutable nsecs_t mNextFakeVSync; + nsecs_t mRefreshPeriod; + HWComposer* mHwc; sp<FramebufferNativeWindow> mNativeWindow; diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index aebe1b8..1846ccb 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -29,167 +29,79 @@ namespace android { // --------------------------------------------------------------------------- -void MessageList::insert(const sp<MessageBase>& node) -{ - LIST::iterator cur(mList.begin()); - LIST::iterator end(mList.end()); - while (cur != end) { - if (*node < **cur) { - mList.insert(cur, node); - return; - } - ++cur; - } - mList.insert(++end, node); +MessageBase::MessageBase() + : MessageHandler() { } -void MessageList::remove(MessageList::LIST::iterator pos) -{ - mList.erase(pos); +MessageBase::~MessageBase() { } +void MessageBase::handleMessage(const Message&) { + this->handler(); + barrier.open(); +}; + // --------------------------------------------------------------------------- MessageQueue::MessageQueue() - : mInvalidate(false) + : mLooper(new Looper(true)), + mInvalidatePending(0) { - mInvalidateMessage = new MessageBase(INVALIDATE); } -MessageQueue::~MessageQueue() -{ +MessageQueue::~MessageQueue() { } -sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout) -{ - sp<MessageBase> result; - - bool again; +void MessageQueue::waitMessage() { do { - const nsecs_t timeoutTime = systemTime() + timeout; - while (true) { - Mutex::Autolock _l(mLock); - nsecs_t now = systemTime(); - nsecs_t nextEventTime = -1; - - LIST::iterator cur(mMessages.begin()); - if (cur != mMessages.end()) { - result = *cur; - } - - if (result != 0) { - if (result->when <= now) { - // there is a message to deliver - mMessages.remove(cur); - break; - } - nextEventTime = result->when; - result = 0; - } - - // see if we have an invalidate message - if (mInvalidate) { - mInvalidate = false; - mInvalidateMessage->when = now; - result = mInvalidateMessage; - break; - } - - if (timeout >= 0) { - if (timeoutTime < now) { - // we timed-out, return a NULL message - result = 0; - break; - } - if (nextEventTime > 0) { - if (nextEventTime > timeoutTime) { - nextEventTime = timeoutTime; - } - } else { - nextEventTime = timeoutTime; - } - } - - if (nextEventTime >= 0) { - //LOGD("nextEventTime = %lld ms", nextEventTime); - if (nextEventTime > 0) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - const nsecs_t reltime = nextEventTime - systemTime(); - if (reltime > 0) { - mCondition.waitRelative(mLock, reltime); - } - } - } else { - //LOGD("going to wait"); - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - mCondition.wait(mLock); - } - } - // here we're not holding the lock anymore - - if (result == 0) + // handle invalidate events first + if (android_atomic_and(0, &mInvalidatePending) != 0) break; - again = result->handler(); - if (again) { - // the message has been processed. release our reference to it - // without holding the lock. - result->notify(); - result = 0; - } - - } while (again); + IPCThreadState::self()->flushCommands(); - return result; -} + int32_t ret = mLooper->pollOnce(-1); + switch (ret) { + case ALOOPER_POLL_WAKE: + // we got woken-up there is work to do in the main loop + continue; -status_t MessageQueue::postMessage( - const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) -{ - return queueMessage(message, relTime, flags); -} + case ALOOPER_POLL_CALLBACK: + // callback was handled, loop again + continue; -status_t MessageQueue::invalidate() { - Mutex::Autolock _l(mLock); - mInvalidate = true; - mCondition.signal(); - return NO_ERROR; -} + case ALOOPER_POLL_TIMEOUT: + // timeout (should not happen) + continue; -status_t MessageQueue::queueMessage( - const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags) -{ - Mutex::Autolock _l(mLock); - message->when = systemTime() + relTime; - mMessages.insert(message); - - //LOGD("MessageQueue::queueMessage time = %lld ms", message->when); - //dumpLocked(message); - - mCondition.signal(); - return NO_ERROR; -} + case ALOOPER_POLL_ERROR: + LOGE("ALOOPER_POLL_ERROR"); + continue; -void MessageQueue::dump(const sp<MessageBase>& message) -{ - Mutex::Autolock _l(mLock); - dumpLocked(message); + default: + // should not happen + LOGE("Looper::pollOnce() returned unknown status %d", ret); + continue; + } + } while (true); } -void MessageQueue::dumpLocked(const sp<MessageBase>& message) +status_t MessageQueue::postMessage( + const sp<MessageBase>& messageHandler, nsecs_t relTime) { - LIST::const_iterator cur(mMessages.begin()); - LIST::const_iterator end(mMessages.end()); - int c = 0; - while (cur != end) { - const char tick = (*cur == message) ? '>' : ' '; - LOGD("%c %d: msg{.what=%08x, when=%lld}", - tick, c, (*cur)->what, (*cur)->when); - ++cur; - c++; + const Message dummyMessage; + if (relTime > 0) { + mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage); + } else { + mLooper->sendMessage(messageHandler, dummyMessage); } + return NO_ERROR; +} + +status_t MessageQueue::invalidate() { + android_atomic_or(1, &mInvalidatePending); + mLooper->wake(); + return NO_ERROR; } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index 890f809..25030a6 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -23,7 +23,7 @@ #include <utils/threads.h> #include <utils/Timers.h> -#include <utils/List.h> +#include <utils/Looper.h> #include "Barrier.h" @@ -31,92 +31,39 @@ namespace android { // --------------------------------------------------------------------------- -class MessageBase; - -class MessageList -{ - List< sp<MessageBase> > mList; - typedef List< sp<MessageBase> > LIST; -public: - inline LIST::iterator begin() { return mList.begin(); } - inline LIST::const_iterator begin() const { return mList.begin(); } - inline LIST::iterator end() { return mList.end(); } - inline LIST::const_iterator end() const { return mList.end(); } - inline bool isEmpty() const { return mList.empty(); } - void insert(const sp<MessageBase>& node); - void remove(LIST::iterator pos); -}; - -// ============================================================================ - -class MessageBase : - public LightRefBase<MessageBase> +class MessageBase : public MessageHandler { public: - nsecs_t when; - uint32_t what; - int32_t arg0; - - MessageBase() : when(0), what(0), arg0(0) { } - MessageBase(uint32_t what, int32_t arg0=0) - : when(0), what(what), arg0(arg0) { } + MessageBase(); // return true if message has a handler - virtual bool handler() { return false; } + virtual bool handler() = 0; // waits for the handler to be processed void wait() const { barrier.wait(); } - - // releases all waiters. this is done automatically if - // handler returns true - void notify() const { barrier.open(); } protected: - virtual ~MessageBase() { } + virtual ~MessageBase(); private: + virtual void handleMessage(const Message& message); + mutable Barrier barrier; - friend class LightRefBase<MessageBase>; }; -inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) { - return lhs.when < rhs.when; -} - // --------------------------------------------------------------------------- -class MessageQueue -{ - typedef List< sp<MessageBase> > LIST; -public: +class MessageQueue { + sp<Looper> mLooper; + volatile int32_t mInvalidatePending; +public: MessageQueue(); ~MessageQueue(); - // pre-defined messages - enum { - INVALIDATE = '_upd' - }; - - sp<MessageBase> waitMessage(nsecs_t timeout = -1); - - status_t postMessage(const sp<MessageBase>& message, - nsecs_t reltime=0, uint32_t flags = 0); - + void waitMessage(); + status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0); status_t invalidate(); - - void dump(const sp<MessageBase>& message); - -private: - status_t queueMessage(const sp<MessageBase>& message, - nsecs_t reltime, uint32_t flags); - void dumpLocked(const sp<MessageBase>& message); - - Mutex mLock; - Condition mCondition; - MessageList mMessages; - bool mInvalidate; - sp<MessageBase> mInvalidateMessage; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1b00e93..d5a8d08 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -34,6 +34,8 @@ #include <binder/MemoryHeapBase.h> #include <binder/PermissionCache.h> +#include <gui/IDisplayEventConnection.h> + #include <utils/String8.h> #include <utils/String16.h> #include <utils/StopWatch.h> @@ -46,6 +48,8 @@ #include <GLES/gl.h> #include "clz.h" +#include "DisplayEventConnection.h" +#include "EventThread.h" #include "GLExtensions.h" #include "DdmConnection.h" #include "Layer.h" @@ -293,12 +297,16 @@ status_t SurfaceFlinger::readyToRun() // put the origin in the left-bottom corner glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h - mReadyToRunBarrier.open(); + + // start the EventThread + mEventThread = new EventThread(this); /* * We're now ready to accept clients... */ + mReadyToRunBarrier.open(); + // start boot animation property_set("ctl.start", "bootanim"); @@ -311,25 +319,30 @@ status_t SurfaceFlinger::readyToRun() #pragma mark Events Handler #endif -void SurfaceFlinger::waitForEvent() -{ - while (true) { - nsecs_t timeout = -1; - sp<MessageBase> msg = mEventQueue.waitMessage(timeout); - if (msg != 0) { - switch (msg->what) { - case MessageQueue::INVALIDATE: - // invalidate message, just return to the main loop - return; - } - } - } +void SurfaceFlinger::waitForEvent() { + mEventQueue.waitMessage(); } void SurfaceFlinger::signalEvent() { mEventQueue.invalidate(); } +status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t flags) { + return mEventQueue.postMessage(msg, reltime); +} + +status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t flags) { + status_t res = mEventQueue.postMessage(msg, reltime); + if (res == NO_ERROR) { + msg->wait(); + } + return res; +} + +// ---------------------------------------------------------------------------- + bool SurfaceFlinger::authenticateSurfaceTexture( const sp<ISurfaceTexture>& surfaceTexture) const { Mutex::Autolock _l(mStateLock); @@ -371,20 +384,17 @@ bool SurfaceFlinger::authenticateSurfaceTexture( return false; } -status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t flags) -{ - return mEventQueue.postMessage(msg, reltime, flags); +// ---------------------------------------------------------------------------- + +sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { + sp<DisplayEventConnection> result(new DisplayEventConnection(this)); + mEventThread->registerDisplayEventConnection(result); + return result; } -status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, - nsecs_t reltime, uint32_t flags) -{ - status_t res = mEventQueue.postMessage(msg, reltime, flags); - if (res == NO_ERROR) { - msg->wait(); - } - return res; +void SurfaceFlinger::cleanupDisplayEventConnection( + const wp<DisplayEventConnection>& connection) { + mEventThread->unregisterDisplayEventConnection(connection); } // ---------------------------------------------------------------------------- @@ -443,7 +453,7 @@ bool SurfaceFlinger::threadLoop() } else { // pretend we did the post hw.compositionComplete(); - usleep(16667); // 60 fps period + hw.waitForVSync(); } return true; } @@ -1583,9 +1593,16 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } /* + * VSYNC state + */ + mEventThread->dump(result, buffer, SIZE); + + /* * Dump HWComposer state */ HWComposer& hwc(hw.getHwComposer()); + snprintf(buffer, SIZE, "h/w composer state:\n"); + result.append(buffer); snprintf(buffer, SIZE, " h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 17028db..1039f47 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -46,6 +46,8 @@ namespace android { class Client; class DisplayHardware; +class DisplayEventConnection; +class EventThread; class Layer; class LayerDim; class LayerScreenshot; @@ -171,6 +173,7 @@ public: int orientation, uint32_t flags); virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags); virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const; + virtual sp<IDisplayEventConnection> createDisplayEventConnection(); virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, @@ -222,6 +225,7 @@ private: private: friend class Client; + friend class DisplayEventConnection; friend class LayerBase; friend class LayerBaseClient; friend class Layer; @@ -331,6 +335,9 @@ private: status_t electronBeamOffAnimationImplLocked(); status_t electronBeamOnAnimationImplLocked(); + void cleanupDisplayEventConnection( + const wp<DisplayEventConnection>& connection); + void debugFlashRegions(); void debugShowFPS() const; void drawWormhole() const; @@ -361,6 +368,7 @@ private: GLuint mWormholeTexName; GLuint mProtectedTexName; nsecs_t mBootTime; + sp<EventThread> mEventThread; // Can only accessed from the main thread, these members // don't need synchronization |