Add support for sending VSYNC events to the framework
use gui/DisplayEvent to receive the events. Events are
dispatched through a unix pipe, so the API is compatible
with utils/Looper. see gui/DisplayEvent.h for more info.
Bug: 1475048
Change-Id: If4126023fc9c067e56087ec7d16a8fd542ce1794
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 5eb09c7..58fd89d 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -33,8 +33,9 @@
namespace android {
// ----------------------------------------------------------------------------
-class IMemoryHeap;
class ComposerState;
+class IDisplayEventConnection;
+class IMemoryHeap;
class ISurfaceComposer : public IInterface
{
@@ -124,13 +125,19 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
+ /* triggers screen off animation */
virtual status_t turnElectronBeamOff(int32_t mode) = 0;
+
+ /* triggers screen on animation */
virtual status_t turnElectronBeamOn(int32_t mode) = 0;
/* verify that an ISurfaceTexture was created by SurfaceFlinger.
*/
virtual bool authenticateSurfaceTexture(
const sp<ISurfaceTexture>& surface) const = 0;
+
+ /* return an IDisplayEventConnection */
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
};
// ----------------------------------------------------------------------------
@@ -151,6 +158,7 @@
TURN_ELECTRON_BEAM_OFF,
TURN_ELECTRON_BEAM_ON,
AUTHENTICATE_SURFACE,
+ CREATE_DISPLAY_EVENT_CONNECTION,
};
virtual status_t onTransact( uint32_t code,
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b7e3ee3..b8be67d 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,6 +3,8 @@
LOCAL_SRC_FILES:= \
BitTube.cpp \
+ DisplayEventReceiver.cpp \
+ IDisplayEventConnection.cpp \
ISensorEventConnection.cpp \
ISensorServer.cpp \
ISurfaceTexture.cpp \
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 86bc62a..db32827 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -29,6 +29,9 @@
#include <surfaceflinger/ISurfaceComposer.h>
+#include <gui/BitTube.h>
+#include <gui/IDisplayEventConnection.h>
+
#include <ui/DisplayInfo.h>
#include <gui/ISurfaceTexture.h>
@@ -44,6 +47,8 @@
namespace android {
+class IDisplayEventConnection;
+
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{
public:
@@ -174,6 +179,27 @@
}
return result != 0;
}
+
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection()
+ {
+ Parcel data, reply;
+ sp<IDisplayEventConnection> result;
+ int err = data.writeInterfaceToken(
+ ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ return result;
+ }
+ err = remote()->transact(
+ BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
+ data, &reply);
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::createDisplayEventConnection: error performing "
+ "transaction: %s (%d)", strerror(-err), -err);
+ return result;
+ }
+ result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
+ return result;
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -254,6 +280,12 @@
int32_t result = authenticateSurfaceTexture(surfaceTexture) ? 1 : 0;
reply->writeInt32(result);
} break;
+ case CREATE_DISPLAY_EVENT_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IDisplayEventConnection> connection(createDisplayEventConnection());
+ reply->writeStrongBinder(connection->asBinder());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 61a8358..17bf375 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,19 +2,22 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 39f0f40..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 @@
// 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");
@@ -319,6 +327,22 @@
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);
@@ -360,20 +384,17 @@
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);
}
// ----------------------------------------------------------------------------
@@ -432,7 +453,7 @@
} else {
// pretend we did the post
hw.compositionComplete();
- usleep(16667); // 60 fps period
+ hw.waitForVSync();
}
return true;
}
@@ -1572,9 +1593,16 @@
}
/*
+ * 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 @@
class Client;
class DisplayHardware;
+class DisplayEventConnection;
+class EventThread;
class Layer;
class LayerDim;
class LayerScreenshot;
@@ -171,6 +173,7 @@
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:
friend class Client;
+ friend class DisplayEventConnection;
friend class LayerBase;
friend class LayerBaseClient;
friend class Layer;
@@ -331,6 +335,9 @@
status_t electronBeamOffAnimationImplLocked();
status_t electronBeamOnAnimationImplLocked();
+ void cleanupDisplayEventConnection(
+ const wp<DisplayEventConnection>& connection);
+
void debugFlashRegions();
void debugShowFPS() const;
void drawWormhole() const;
@@ -361,6 +368,7 @@
GLuint mWormholeTexName;
GLuint mProtectedTexName;
nsecs_t mBootTime;
+ sp<EventThread> mEventThread;
// Can only accessed from the main thread, these members
// don't need synchronization