Merge "Fixed disconnect bug in SurfaceTexture"
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 8414ff6..65ccb8d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -254,6 +254,14 @@
AKEYCODE_CALENDAR = 208,
AKEYCODE_MUSIC = 209,
AKEYCODE_CALCULATOR = 210,
+ AKEYCODE_ZENKAKU_HANKAKU = 211,
+ AKEYCODE_EISU = 212,
+ AKEYCODE_MUHENKAN = 213,
+ AKEYCODE_HENKAN = 214,
+ AKEYCODE_KATAKANA_HIRAGANA = 215,
+ AKEYCODE_YEN = 216,
+ AKEYCODE_RO = 217,
+ AKEYCODE_KANA = 218,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index 76389a0..3022d05 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -22,6 +22,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <cutils/log.h>
namespace android {
@@ -43,9 +44,27 @@
status_t writeToParcel(Parcel* reply) const;
+ template <typename T>
+ static ssize_t sendObjects(const sp<BitTube>& tube,
+ T const* events, size_t count) {
+ return sendObjects(tube, events, count, sizeof(T));
+ }
+
+ template <typename T>
+ static ssize_t recvObjects(const sp<BitTube>& tube,
+ T* events, size_t count) {
+ return recvObjects(tube, events, count, sizeof(T));
+ }
+
private:
int mSendFd;
mutable int mReceiveFd;
+
+ static ssize_t sendObjects(const sp<BitTube>& tube,
+ void const* events, size_t count, size_t objSize);
+
+ static ssize_t recvObjects(const sp<BitTube>& tube,
+ void* events, size_t count, size_t objSize);
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index 7bca8d6..e631cca 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -89,7 +89,7 @@
int getFd() const;
/*
- * getEvents reads event from the queue and returns how many events were
+ * getEvents reads events from the queue and returns how many events were
* read. Returns 0 if there are no more events or a negative error code.
* If NOT_ENOUGH_DATA is returned, the object has become invalid forever, it
* should be destroyed and getEvents() shouldn't be called again.
@@ -99,6 +99,13 @@
Event* events, size_t count);
/*
+ * sendEvents write events to the queue and returns how many events were
+ * written.
+ */
+ static ssize_t sendEvents(const sp<BitTube>& dataChannel,
+ Event const* events, size_t count);
+
+ /*
* setVsyncRate() sets the Event::VSync delivery rate. A value of
* 1 returns every Event::VSync. A value of 2 returns every other event,
* etc... a value of 0 returns no event unless requestNextVsync() has
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index ef7c6e3..759b5cb 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -54,7 +54,10 @@
virtual void onFirstRef();
int getFd() const;
- ssize_t write(ASensorEvent const* events, size_t numEvents);
+
+ static ssize_t write(const sp<BitTube>& tube,
+ ASensorEvent const* events, size_t numEvents);
+
ssize_t read(ASensorEvent* events, size_t numEvents);
status_t waitForEvent() const;
diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h
new file mode 100644
index 0000000..81d9601
--- /dev/null
+++ b/include/media/hardware/CryptoAPI.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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 <utils/Errors.h>
+
+#ifndef CRYPTO_API_H_
+
+#define CRYPTO_API_H_
+
+namespace android {
+
+struct CryptoPlugin;
+
+struct CryptoFactory {
+ CryptoFactory() {}
+ virtual ~CryptoFactory() {}
+
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
+
+ virtual status_t createPlugin(
+ const uint8_t uuid[16], const void *data, size_t size,
+ CryptoPlugin **plugin) = 0;
+
+private:
+ CryptoFactory(const CryptoFactory &);
+ CryptoFactory &operator=(const CryptoFactory &);
+};
+
+struct CryptoPlugin {
+ enum Mode {
+ kMode_Unencrypted = 0,
+ kMode_AES_CTR = 1,
+
+ // Neither key nor iv are being used in this mode.
+ // Each subsample is encrypted w/ an iv of all zeroes.
+ kMode_AES_WV = 2, // FIX constant
+ };
+
+ struct SubSample {
+ size_t mNumBytesOfClearData;
+ size_t mNumBytesOfEncryptedData;
+ };
+
+ CryptoPlugin() {}
+ virtual ~CryptoPlugin() {}
+
+ // If this method returns false, a non-secure decoder will be used to
+ // decode the data after decryption. The decrypt API below will have
+ // to support insecure decryption of the data (secure = false) for
+ // media data of the given mime type.
+ virtual bool requiresSecureDecoderComponent(const char *mime) const = 0;
+
+ virtual status_t decrypt(
+ bool secure,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ Mode mode,
+ const void *srcPtr,
+ const SubSample *subSamples, size_t numSubSamples,
+ void *dstPtr) = 0;
+
+private:
+ CryptoPlugin(const CryptoPlugin &);
+ CryptoPlugin &operator=(const CryptoPlugin &);
+};
+
+} // namespace android
+
+extern "C" {
+ extern android::CryptoFactory *createCryptoFactory();
+}
+
+#endif // CRYPTO_API_H_
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 55f4178..355a319 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -16,9 +16,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <fcntl.h>
-#include <signal.h>
#include <unistd.h>
#include <utils/Errors.h>
@@ -30,17 +30,25 @@
namespace android {
// ----------------------------------------------------------------------------
+// Socket buffer size. The default is typically about 128KB, which is much larger than
+// we really need. So we make it smaller.
+static const size_t SOCKET_BUFFER_SIZE = 4 * 1024;
+
+
BitTube::BitTube()
: mSendFd(-1), mReceiveFd(-1)
{
- int fds[2];
- if (pipe(fds) == 0) {
- mReceiveFd = fds[0];
- mSendFd = fds[1];
- fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
- fcntl(mSendFd, F_SETFL, O_NONBLOCK);
- // ignore SIGPIPE, we handle write errors through EPIPE instead
- signal(SIGPIPE, SIG_IGN);
+ int sockets[2];
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
+ int size = SOCKET_BUFFER_SIZE;
+ setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+ setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+ setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+ setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+ fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+ fcntl(sockets[1], F_SETFL, O_NONBLOCK);
+ mReceiveFd = sockets[0];
+ mSendFd = sockets[1];
} else {
mReceiveFd = -errno;
ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
@@ -52,6 +60,9 @@
{
mReceiveFd = dup(data.readFileDescriptor());
if (mReceiveFd >= 0) {
+ int size = SOCKET_BUFFER_SIZE;
+ setsockopt(mReceiveFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+ setsockopt(mReceiveFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
} else {
mReceiveFd = -errno;
@@ -86,7 +97,7 @@
{
ssize_t err, len;
do {
- len = ::write(mSendFd, vaddr, size);
+ len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
err = len < 0 ? errno : 0;
} while (err == EINTR);
return err == 0 ? len : -err;
@@ -97,7 +108,7 @@
{
ssize_t err, len;
do {
- len = ::read(mReceiveFd, vaddr, size);
+ len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
err = len < 0 ? errno : 0;
} while (err == EINTR);
if (err == EAGAIN || err == EWOULDBLOCK) {
@@ -119,5 +130,46 @@
return result;
}
+
+ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
+ void const* events, size_t count, size_t objSize)
+{
+ ssize_t numObjects = 0;
+ for (size_t i=0 ; i<count ; i++) {
+ const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
+ ssize_t size = tube->write(vaddr, objSize);
+ if (size < 0) {
+ // error occurred
+ numObjects = -size;
+ break;
+ } else if (size == 0) {
+ // no more space
+ break;
+ }
+ numObjects++;
+ }
+ return numObjects;
+}
+
+ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
+ void* events, size_t count, size_t objSize)
+{
+ ssize_t numObjects = 0;
+ for (size_t i=0 ; i<count ; i++) {
+ char* vaddr = reinterpret_cast<char*>(events) + objSize * i;
+ ssize_t size = tube->read(vaddr, objSize);
+ if (size < 0) {
+ // error occurred
+ numObjects = -size;
+ break;
+ } else if (size == 0) {
+ // no more messages
+ break;
+ }
+ numObjects++;
+ }
+ return numObjects;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index a6790ad..9973e8d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -85,22 +85,13 @@
ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
Event* events, size_t count)
{
- ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
- ALOGE_IF(size<0,
- "DisplayEventReceiver::getEvents error (%s)",
- strerror(-size));
- if (size >= 0) {
- // Note: if (size % sizeof(events[0])) != 0, we've got a
- // partial read. This can happen if the queue filed up (ie: if we
- // didn't pull from it fast enough).
- // We discard the partial event and rely on the sender to
- // re-send the event if appropriate (some events, like VSYNC
- // can be lost forever).
+ return BitTube::recvObjects(dataChannel, events, count);
+}
- // returns number of events read
- size /= sizeof(events[0]);
- }
- return size;
+ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
+ Event const* events, size_t count)
+{
+ return BitTube::sendObjects(dataChannel, events, count);
}
// ---------------------------------------------------------------------------
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index b95dd90..04ba640 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -53,36 +53,15 @@
return mSensorChannel->getFd();
}
-ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents)
-{
- ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0]));
- if (size >= 0) {
- if (size % sizeof(events[0])) {
- // partial write!!! should never happen.
- return -EINVAL;
- }
- // returns number of events written
- size /= sizeof(events[0]);
- }
- return size;
+
+ssize_t SensorEventQueue::write(const sp<BitTube>& tube,
+ ASensorEvent const* events, size_t numEvents) {
+ return BitTube::sendObjects(tube, events, numEvents);
}
ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
{
- ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
- ALOGE_IF(size<0 && size!=-EAGAIN,
- "SensorChannel::read error (%s)", strerror(-size));
- if (size >= 0) {
- if (size % sizeof(events[0])) {
- // partial read!!! should never happen.
- ALOGE("SensorEventQueue partial read (event-size=%u, read=%d)",
- sizeof(events[0]), int(size));
- return -EINVAL;
- }
- // returns number of events read
- size /= sizeof(events[0]);
- }
- return size;
+ return BitTube::recvObjects(mSensorChannel, events, numEvents);
}
sp<Looper> SensorEventQueue::getLooper() const
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 702b52b..d2e0110 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,8 +10,6 @@
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
DisplayHardware/HWComposer.cpp \
- DisplayHardware/VSyncBarrier.cpp \
- DisplayEventConnection.cpp \
GLExtensions.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp
deleted file mode 100644
index 77ecbd2..0000000
--- a/services/surfaceflinger/DisplayEventConnection.cpp
+++ /dev/null
@@ -1,71 +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 <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IDisplayEventConnection.h>
-#include <gui/BitTube.h>
-#include <gui/DisplayEventReceiver.h>
-
-#include <utils/Errors.h>
-
-#include "SurfaceFlinger.h"
-#include "DisplayEventConnection.h"
-#include "EventThread.h"
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-DisplayEventConnection::DisplayEventConnection(
- const sp<EventThread>& eventThread)
- : mEventThread(eventThread), mChannel(new BitTube())
-{
-}
-
-DisplayEventConnection::~DisplayEventConnection() {
- mEventThread->unregisterDisplayEventConnection(this);
-}
-
-void DisplayEventConnection::onFirstRef() {
- // NOTE: mEventThread doesn't hold a strong reference on us
- mEventThread->registerDisplayEventConnection(this);
-}
-
-sp<BitTube> DisplayEventConnection::getDataChannel() const {
- return mChannel;
-}
-
-void DisplayEventConnection::setVsyncRate(uint32_t count) {
- mEventThread->setVsyncRate(count, this);
-}
-
-void DisplayEventConnection::requestNextVsync() {
- mEventThread->requestNextVsync(this);
-}
-
-status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
-{
- ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
- return size < 0 ? status_t(size) : status_t(NO_ERROR);
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h
deleted file mode 100644
index cc3ee36..0000000
--- a/services/surfaceflinger/DisplayEventConnection.h
+++ /dev/null
@@ -1,62 +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_DISPLAY_EVENT_CONNECTION_H
-#define ANDROID_SURFACE_FLINGER_DISPLAY_EVENT_CONNECTION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IDisplayEventConnection.h>
-
-#include <utils/Errors.h>
-#include <gui/DisplayEventReceiver.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class BitTube;
-class EventThread;
-
-// ---------------------------------------------------------------------------
-
-class DisplayEventConnection : public BnDisplayEventConnection {
-public:
- DisplayEventConnection(const sp<EventThread>& flinger);
-
- status_t postEvent(const DisplayEventReceiver::Event& event);
-
-private:
- virtual ~DisplayEventConnection();
- virtual void onFirstRef();
- virtual sp<BitTube> getDataChannel() const;
- virtual void setVsyncRate(uint32_t count);
- virtual void requestNextVsync(); // asynchronous
-
- sp<EventThread> const mEventThread;
- sp<BitTube> const mChannel;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SURFACE_FLINGER_DISPLAY_EVENT_CONNECTION_H */
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index b7584b3..c46e630 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -35,6 +35,7 @@
#include <hardware/gralloc.h>
+#include "DisplayHardwareBase.h"
#include "GLExtensions.h"
#include "HWComposer.h"
#include "SurfaceFlinger.h"
@@ -160,7 +161,6 @@
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 @@
// 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<VSyncHandler>& handler) {
+ Mutex::Autolock _l(mLock);
+ mVSyncHandler = handler;
+}
+
+void DisplayHardware::onVSyncReceived(int dpy, nsecs_t timestamp) {
+ sp<VSyncHandler> 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 @@
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 @@
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 0a828b3..84a3eff 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 @@
const sp<SurfaceFlinger>& flinger,
uint32_t displayIndex);
- ~DisplayHardware();
+ virtual ~DisplayHardware();
void releaseScreen() const;
void acquireScreen() const;
@@ -69,14 +78,15 @@
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<VSyncHandler>& handler);
+
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -94,9 +104,9 @@
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<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
@@ -114,15 +124,18 @@
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<VSyncHandler> mVSyncHandler;
+
sp<FramebufferNativeWindow> mNativeWindow;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f17bf43..e742d3e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -22,9 +22,11 @@
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/Thread.h>
#include <utils/Vector.h>
#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
#include <cutils/log.h>
@@ -37,11 +39,16 @@
namespace android {
// ---------------------------------------------------------------------------
-HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+HWComposer::HWComposer(
+ const sp<SurfaceFlinger>& 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);
@@ -53,7 +60,14 @@
if (mHwc->registerProcs) {
mCBContext.hwc = this;
mCBContext.procs.invalidate = &hook_invalidate;
+ mCBContext.procs.vsync = &hook_vsync;
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);
}
}
}
@@ -61,6 +75,9 @@
HWComposer::~HWComposer() {
free(mList);
+ if (mVSyncThread != NULL) {
+ mVSyncThread->requestExitAndWait();
+ }
if (mHwc) {
hwc_close(mHwc);
}
@@ -74,10 +91,32 @@
reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
}
+void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) {
+ reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);
+}
+
void HWComposer::invalidate() {
mFlinger->repaintEverything();
}
+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) {
mDpy = (hwc_display_t)dpy;
mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index aa8ebe1..60a6367 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -27,6 +27,10 @@
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
+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 HWComposer
{
public:
+ class EventHandler {
+ friend class HWComposer;
+ virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+ protected:
+ virtual ~EventHandler() {}
+ };
- HWComposer(const sp<SurfaceFlinger>& flinger);
+ HWComposer(const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler, nsecs_t refreshPeriod);
~HWComposer();
status_t initCheck() const;
@@ -46,7 +57,7 @@
// 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,23 +72,108 @@
// 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<LayerBase> >& visibleLayersSortedByZ) const;
private:
+
+ struct callbacks : public hwc_procs_t {
+ // these are here to facilitate the transition when adding
+ // new callbacks (an implementation can check for NULL before
+ // calling a new callback).
+ void (*zero[4])(void);
+ };
+
struct cb_context {
- hwc_procs_t procs;
+ callbacks procs;
HWComposer* hwc;
};
+
static void hook_invalidate(struct hwc_procs* procs);
- void invalidate();
+ static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
+
+ inline void invalidate();
+ inline void vsync(int dpy, int64_t timestamp);
sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
@@ -89,6 +185,9 @@
hwc_display_t mDpy;
hwc_surface_t mSur;
cb_context mCBContext;
+ EventHandler& mEventHandler;
+ nsecs_t mRefreshPeriod;
+ sp<VSyncThread> mVSyncThread;
};
diff --git a/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp b/services/surfaceflinger/DisplayHardware/VSyncBarrier.cpp
deleted file mode 100644
index 187da20..0000000
--- 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 <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-
-#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 3c32950..0000000
--- 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 <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-
-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 3c045d7..b05b7c2 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <gui/BitTube.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/DisplayEventReceiver.h>
@@ -26,7 +27,6 @@
#include <utils/Trace.h>
#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayEventConnection.h"
#include "EventThread.h"
#include "SurfaceFlinger.h"
@@ -38,18 +38,20 @@
EventThread::EventThread(const sp<SurfaceFlinger>& 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);
}
-sp<DisplayEventConnection> EventThread::createEventConnection() const {
- return new DisplayEventConnection(const_cast<EventThread*>(this));
+sp<EventThread::Connection> EventThread::createEventConnection() const {
+ return new Connection(const_cast<EventThread*>(this));
}
nsecs_t EventThread::getLastVSyncTimestamp() const {
@@ -63,132 +65,135 @@
}
status_t EventThread::registerDisplayEventConnection(
- const sp<DisplayEventConnection>& connection) {
+ const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
- ConnectionInfo info;
- mDisplayEventConnections.add(connection, info);
+ mDisplayEventConnections.add(connection);
mCondition.signal();
return NO_ERROR;
}
status_t EventThread::unregisterDisplayEventConnection(
- const wp<DisplayEventConnection>& connection) {
+ const wp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.removeItem(connection);
+ mDisplayEventConnections.remove(connection);
mCondition.signal();
return NO_ERROR;
}
void EventThread::removeDisplayEventConnection(
- const wp<DisplayEventConnection>& connection) {
+ const wp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
- mDisplayEventConnections.removeItem(connection);
-}
-
-EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
- const wp<DisplayEventConnection>& connection) {
- ssize_t index = mDisplayEventConnections.indexOfKey(connection);
- if (index < 0) return NULL;
- return &mDisplayEventConnections.editValueAt(index);
+ mDisplayEventConnections.remove(connection);
}
void EventThread::setVsyncRate(uint32_t count,
- const wp<DisplayEventConnection>& connection) {
+ const sp<EventThread::Connection>& connection) {
if (int32_t(count) >= 0) { // server must protect against bad params
Mutex::Autolock _l(mLock);
- ConnectionInfo* info = getConnectionInfoLocked(connection);
- if (info) {
- const int32_t new_count = (count == 0) ? -1 : count;
- if (info->count != new_count) {
- info->count = new_count;
- mCondition.signal();
- }
+ const int32_t new_count = (count == 0) ? -1 : count;
+ if (connection->count != new_count) {
+ connection->count = new_count;
+ mCondition.signal();
}
}
}
void EventThread::requestNextVsync(
- const wp<DisplayEventConnection>& connection) {
+ const sp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
- ConnectionInfo* info = getConnectionInfoLocked(connection);
- if (info && info->count < 0) {
- info->count = 0;
+ if (connection->count < 0) {
+ connection->count = 0;
mCondition.signal();
}
}
+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<DisplayEventConnection> > displayEventConnections;
+ Vector< wp<EventThread::Connection> > 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<count ; i++) {
- const ConnectionInfo& info(
- mDisplayEventConnections.valueAt(i));
- if (info.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<count ; i++) {
- bool reportVsync = false;
- const ConnectionInfo& info(
- mDisplayEventConnections.valueAt(i));
- if (info.count >= 1) {
- if (info.count==1 || (mDeliveredEvents % info.count) == 0) {
- // continuous event, and time to report it
- reportVsync = true;
- }
- } else if (info.count >= -1) {
- ConnectionInfo& info(
- mDisplayEventConnections.editValueAt(i));
- if (info.count == 0) {
- // fired this time around
- reportVsync = true;
- }
- info.count--;
- }
- if (reportVsync) {
- displayEventConnections.add(mDisplayEventConnections.keyAt(i));
+ sp<Connection> connection =
+ mDisplayEventConnections.itemAt(i).promote();
+ 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<count ; i++) {
+ bool reportVsync = false;
+ sp<Connection> 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<count ; i++) {
- sp<DisplayEventConnection> conn(displayEventConnections[i].promote());
+ sp<Connection> conn(displayEventConnections[i].promote());
// make sure the connection didn't die
if (conn != NULL) {
status_t err = conn->postEvent(vsync);
@@ -232,4 +237,39 @@
// ---------------------------------------------------------------------------
+EventThread::Connection::Connection(
+ const sp<EventThread>& eventThread)
+ : count(-1), mEventThread(eventThread), mChannel(new BitTube())
+{
+}
+
+EventThread::Connection::~Connection() {
+ mEventThread->unregisterDisplayEventConnection(this);
+}
+
+void EventThread::Connection::onFirstRef() {
+ // NOTE: mEventThread doesn't hold a strong reference on us
+ mEventThread->registerDisplayEventConnection(this);
+}
+
+sp<BitTube> EventThread::Connection::getDataChannel() const {
+ return mChannel;
+}
+
+void EventThread::Connection::setVsyncRate(uint32_t count) {
+ mEventThread->setVsyncRate(count, this);
+}
+
+void EventThread::Connection::requestNextVsync() {
+ mEventThread->requestNextVsync(this);
+}
+
+status_t EventThread::Connection::postEvent(
+ const DisplayEventReceiver::Event& event) {
+ ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+// ---------------------------------------------------------------------------
+
}; // namespace android
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 3a3071e..3f9d452 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -20,13 +20,14 @@
#include <stdint.h>
#include <sys/types.h>
+#include <gui/DisplayEventReceiver.h>
#include <gui/IDisplayEventConnection.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
-#include "DisplayEventConnection.h"
+#include "DisplayHardware/DisplayHardware.h"
// ---------------------------------------------------------------------------
@@ -35,32 +36,43 @@
// ---------------------------------------------------------------------------
class SurfaceFlinger;
-class DisplayHardware;
-class DisplayEventConnection;
// ---------------------------------------------------------------------------
-class EventThread : public Thread {
- friend class DisplayEventConnection;
+class EventThread : public Thread, public DisplayHardware::VSyncHandler {
+ class Connection : public BnDisplayEventConnection {
+ public:
+ Connection(const sp<EventThread>& eventThread);
+ status_t postEvent(const DisplayEventReceiver::Event& event);
+
+ // count >= 1 : continuous event. count is the vsync rate
+ // count == 0 : one-shot event that has not fired
+ // count ==-1 : one-shot event that fired this round / disabled
+ // count ==-2 : one-shot event that fired the round before
+ int32_t count;
+
+ private:
+ virtual ~Connection();
+ virtual void onFirstRef();
+ virtual sp<BitTube> getDataChannel() const;
+ virtual void setVsyncRate(uint32_t count);
+ virtual void requestNextVsync(); // asynchronous
+ sp<EventThread> const mEventThread;
+ sp<BitTube> const mChannel;
+ };
public:
+
EventThread(const sp<SurfaceFlinger>& flinger);
- sp<DisplayEventConnection> createEventConnection() const;
+ sp<Connection> createEventConnection() const;
+ status_t registerDisplayEventConnection(const sp<Connection>& connection);
+ status_t unregisterDisplayEventConnection(const wp<Connection>& connection);
- status_t registerDisplayEventConnection(
- const sp<DisplayEventConnection>& connection);
-
- status_t unregisterDisplayEventConnection(
- const wp<DisplayEventConnection>& connection);
-
- void setVsyncRate(uint32_t count,
- const wp<DisplayEventConnection>& connection);
-
- void requestNextVsync(const wp<DisplayEventConnection>& connection);
+ void setVsyncRate(uint32_t count, const sp<Connection>& connection);
+ void requestNextVsync(const sp<Connection>& connection);
nsecs_t getLastVSyncTimestamp() const;
-
nsecs_t getVSyncPeriod() const;
void dump(String8& result, char* buffer, size_t SIZE) const;
@@ -69,33 +81,21 @@
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
+ virtual void onVSyncReceived(int, nsecs_t timestamp);
- struct ConnectionInfo {
- ConnectionInfo() : count(-1) { }
-
- // count >= 1 : continuous event. count is the vsync rate
- // count == 0 : one-shot event that has not fired
- // count ==-1 : one-shot event that fired this round / disabled
- // count ==-2 : one-shot event that fired the round before
- int32_t count;
- };
-
- void removeDisplayEventConnection(
- const wp<DisplayEventConnection>& connection);
-
- ConnectionInfo* getConnectionInfoLocked(
- const wp<DisplayEventConnection>& connection);
+ void removeDisplayEventConnection(const wp<Connection>& connection);
// constants
sp<SurfaceFlinger> mFlinger;
- const DisplayHardware& mHw;
+ DisplayHardware& mHw;
mutable Mutex mLock;
mutable Condition mCondition;
// protected by mLock
- KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+ SortedVector< wp<Connection> > mDisplayEventConnections;
nsecs_t mLastVSyncTimestamp;
+ nsecs_t mVSyncTimestamp;
// main thread only
size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0b68aa3..7023e0f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,7 +50,6 @@
#include "clz.h"
#include "DdmConnection.h"
-#include "DisplayEventConnection.h"
#include "EventThread.h"
#include "GLExtensions.h"
#include "Layer.h"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b507877..6fa81db 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -270,8 +270,9 @@
};
struct State {
- State() {
- orientation = ISurfaceComposer::eOrientationDefault;
+ State()
+ : orientation(ISurfaceComposer::eOrientationDefault),
+ orientationFlags(0) {
}
LayerVector layersSortedByZ;
uint8_t orientation;