SurfaceFlinger: Add EventControlThread

This change adds a new thread for calling HWComposer's eventControl
asynchronously.  The DispSync-based vsync approach ends up enabling and
disabling HWComposer's vsync callbacks at arbitrary times, and some HWComposer
implementations do not have these calls optimized.

Bug: 11175503
Change-Id: I719be82bd200b391c61d40863b991c7b59acdfd6
This commit is contained in:
Jamie Gennis 2013-10-14 12:22:52 -07:00
parent 247423751f
commit d1700756ec
5 changed files with 131 additions and 10 deletions

View File

@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \
Client.cpp \ Client.cpp \
DisplayDevice.cpp \ DisplayDevice.cpp \
DispSync.cpp \ DispSync.cpp \
EventControlThread.cpp \
EventThread.cpp \ EventThread.cpp \
FrameTracker.cpp \ FrameTracker.cpp \
Layer.cpp \ Layer.cpp \

View File

@ -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<SurfaceFlinger>& 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

View File

@ -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 <stddef.h>
#include <utils/Mutex.h>
#include <utils/Thread.h>
namespace android {
class SurfaceFlinger;
class EventControlThread: public Thread {
public:
EventControlThread(const sp<SurfaceFlinger>& flinger);
virtual ~EventControlThread() {}
void setVsyncEnabled(bool enabled);
virtual bool threadLoop();
private:
sp<SurfaceFlinger> mFlinger;
bool mVsyncEnabled;
Mutex mMutex;
Condition mCond;
};
}
#endif // ANDROID_DISPSYNC_H

View File

@ -60,6 +60,7 @@
#include "DdmConnection.h" #include "DdmConnection.h"
#include "DisplayDevice.h" #include "DisplayDevice.h"
#include "DispSync.h" #include "DispSync.h"
#include "EventControlThread.h"
#include "EventThread.h" #include "EventThread.h"
#include "Layer.h" #include "Layer.h"
#include "LayerDim.h" #include "LayerDim.h"
@ -592,6 +593,9 @@ void SurfaceFlinger::init() {
mEventThread = new EventThread(vsyncSrc); mEventThread = new EventThread(vsyncSrc);
mEventQueue.setEventThread(mEventThread); mEventQueue.setEventThread(mEventThread);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
// set a fake vsync period if there is no HWComposer // set a fake vsync period if there is no HWComposer
if (mHwc->initCheck() != NO_ERROR) { if (mHwc->initCheck() != NO_ERROR) {
mPrimaryDispSync.setPeriod(16666667); mPrimaryDispSync.setPeriod(16666667);
@ -755,7 +759,8 @@ void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock); Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
mPrimaryDispSync.beginResync(); mPrimaryDispSync.beginResync();
eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true; mPrimaryHWVsyncEnabled = true;
} }
} }
@ -778,7 +783,8 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
if (!mPrimaryHWVsyncEnabled) { if (!mPrimaryHWVsyncEnabled) {
mPrimaryDispSync.beginResync(); mPrimaryDispSync.beginResync();
eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true; mPrimaryHWVsyncEnabled = true;
} }
} }
@ -786,7 +792,8 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
Mutex::Autolock _l(mHWVsyncLock); Mutex::Autolock _l(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) { if (mPrimaryHWVsyncEnabled) {
eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
mEventControlThread->setVsyncEnabled(false);
mPrimaryDispSync.endResync(); mPrimaryDispSync.endResync();
mPrimaryHWVsyncEnabled = false; mPrimaryHWVsyncEnabled = false;
} }
@ -796,15 +803,20 @@ void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
} }
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) { void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
if (type == 0) { bool needsHwVsync = false;
bool needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
if (needsHwVsync) { { // Scope for the lock
enableHardwareVsync(); Mutex::Autolock _l(mHWVsyncLock);
} else { if (type == 0 && mPrimaryHWVsyncEnabled) {
disableHardwareVsync(false); needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
} }
} }
if (needsHwVsync) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
} }
void SurfaceFlinger::onHotplugReceived(int type, bool connected) { void SurfaceFlinger::onHotplugReceived(int type, bool connected) {

View File

@ -67,6 +67,7 @@ class Layer;
class LayerDim; class LayerDim;
class Surface; class Surface;
class RenderEngine; class RenderEngine;
class EventControlThread;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -427,6 +428,7 @@ private:
nsecs_t mBootTime; nsecs_t mBootTime;
bool mGpuToCpuSupported; bool mGpuToCpuSupported;
sp<EventThread> mEventThread; sp<EventThread> mEventThread;
sp<EventControlThread> mEventControlThread;
EGLContext mEGLContext; EGLContext mEGLContext;
EGLConfig mEGLConfig; EGLConfig mEGLConfig;
EGLDisplay mEGLDisplay; EGLDisplay mEGLDisplay;
@ -477,7 +479,6 @@ private:
bool mDaltonize; bool mDaltonize;
}; };
// ---------------------------------------------------------------------------
}; // namespace android }; // namespace android
#endif // ANDROID_SURFACE_FLINGER_H #endif // ANDROID_SURFACE_FLINGER_H