diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index bd89bd5fd..36ad741ea 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ Client.cpp \ DisplayDevice.cpp \ DispSync.cpp \ + EventControlThread.cpp \ EventThread.cpp \ FrameTracker.cpp \ Layer.cpp \ diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp new file mode 100644 index 000000000..65040913f --- /dev/null +++ b/services/surfaceflinger/EventControlThread.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 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 "EventControlThread.h" +#include "SurfaceFlinger.h" + +namespace android { + +EventControlThread::EventControlThread(const sp& flinger): + mFlinger(flinger), + mVsyncEnabled(false) { +} + +void EventControlThread::setVsyncEnabled(bool enabled) { + Mutex::Autolock lock(mMutex); + mVsyncEnabled = enabled; + mCond.signal(); +} + +bool EventControlThread::threadLoop() { + Mutex::Autolock lock(mMutex); + + bool vsyncEnabled = mVsyncEnabled; + + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, + mVsyncEnabled); + + while (true) { + status_t err = mCond.wait(mMutex); + if (err != NO_ERROR) { + ALOGE("error waiting for new events: %s (%d)", + strerror(-err), err); + return false; + } + + if (vsyncEnabled != mVsyncEnabled) { + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); + vsyncEnabled = mVsyncEnabled; + } + } + + return false; +} + +} // namespace android diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h new file mode 100644 index 000000000..be6c53aa3 --- /dev/null +++ b/services/surfaceflinger/EventControlThread.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 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_EVENTCONTROLTHREAD_H +#define ANDROID_EVENTCONTROLTHREAD_H + +#include + +#include +#include + +namespace android { + +class SurfaceFlinger; + +class EventControlThread: public Thread { +public: + + EventControlThread(const sp& flinger); + virtual ~EventControlThread() {} + + void setVsyncEnabled(bool enabled); + virtual bool threadLoop(); + +private: + sp mFlinger; + bool mVsyncEnabled; + + Mutex mMutex; + Condition mCond; +}; + +} + +#endif // ANDROID_DISPSYNC_H diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bc8cfb8a6..8ef4d6f27 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -60,6 +60,7 @@ #include "DdmConnection.h" #include "DisplayDevice.h" #include "DispSync.h" +#include "EventControlThread.h" #include "EventThread.h" #include "Layer.h" #include "LayerDim.h" @@ -592,6 +593,9 @@ void SurfaceFlinger::init() { mEventThread = new EventThread(vsyncSrc); mEventQueue.setEventThread(mEventThread); + mEventControlThread = new EventControlThread(this); + mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); + // set a fake vsync period if there is no HWComposer if (mHwc->initCheck() != NO_ERROR) { mPrimaryDispSync.setPeriod(16666667); @@ -755,7 +759,8 @@ void SurfaceFlinger::enableHardwareVsync() { Mutex::Autolock _l(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mPrimaryDispSync.beginResync(); - eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } @@ -778,7 +783,8 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { if (!mPrimaryHWVsyncEnabled) { mPrimaryDispSync.beginResync(); - eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } } @@ -786,7 +792,8 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { Mutex::Autolock _l(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); + mEventControlThread->setVsyncEnabled(false); mPrimaryDispSync.endResync(); mPrimaryHWVsyncEnabled = false; } @@ -796,15 +803,20 @@ void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { } void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) { - if (type == 0) { - bool needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); + bool needsHwVsync = false; - if (needsHwVsync) { - enableHardwareVsync(); - } else { - disableHardwareVsync(false); + { // Scope for the lock + Mutex::Autolock _l(mHWVsyncLock); + if (type == 0 && mPrimaryHWVsyncEnabled) { + needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); } } + + if (needsHwVsync) { + enableHardwareVsync(); + } else { + disableHardwareVsync(false); + } } void SurfaceFlinger::onHotplugReceived(int type, bool connected) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 353e7ba4b..03c4ba36c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -67,6 +67,7 @@ class Layer; class LayerDim; class Surface; class RenderEngine; +class EventControlThread; // --------------------------------------------------------------------------- @@ -427,6 +428,7 @@ private: nsecs_t mBootTime; bool mGpuToCpuSupported; sp mEventThread; + sp mEventControlThread; EGLContext mEGLContext; EGLConfig mEGLConfig; EGLDisplay mEGLDisplay; @@ -477,7 +479,6 @@ private: bool mDaltonize; }; -// --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SURFACE_FLINGER_H