SurfaceFlinger now uses the new VSYNC HAL API.
If h/w composer doesn't support vsync (version < 0.3) we "fake" it with a timer. Change-Id: I1e3be79f43c9631d1293ad7d6cf52f9bfc42d65b
This commit is contained in:
parent
9d61b955db
commit
3eb38cb33e
|
@ -10,7 +10,6 @@ LOCAL_SRC_FILES:= \
|
|||
DisplayHardware/DisplayHardware.cpp \
|
||||
DisplayHardware/DisplayHardwareBase.cpp \
|
||||
DisplayHardware/HWComposer.cpp \
|
||||
DisplayHardware/VSyncBarrier.cpp \
|
||||
GLExtensions.cpp \
|
||||
MessageQueue.cpp \
|
||||
SurfaceFlinger.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 @@ void DisplayHardware::init(uint32_t dpy)
|
|||
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 @@ void DisplayHardware::init(uint32_t dpy)
|
|||
|
||||
|
||||
// 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 @@ uint32_t DisplayHardware::getPageFlipCount() const {
|
|||
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 @@ nsecs_t DisplayHardware::getRefreshPeriod() const {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -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 @@ public:
|
|||
const sp<SurfaceFlinger>& flinger,
|
||||
uint32_t displayIndex);
|
||||
|
||||
~DisplayHardware();
|
||||
virtual ~DisplayHardware();
|
||||
|
||||
void releaseScreen() const;
|
||||
void acquireScreen() const;
|
||||
|
@ -69,14 +78,15 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ private:
|
|||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -57,12 +64,20 @@ HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HWComposer::~HWComposer() {
|
||||
free(mList);
|
||||
if (mVSyncThread != NULL) {
|
||||
mVSyncThread->requestExitAndWait();
|
||||
}
|
||||
if (mHwc) {
|
||||
hwc_close(mHwc);
|
||||
}
|
||||
|
@ -85,6 +100,21 @@ void HWComposer::invalidate() {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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 LayerBase;
|
|||
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 @@ public:
|
|||
// 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,13 +72,86 @@ public:
|
|||
// 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;
|
||||
|
||||
|
@ -88,8 +172,8 @@ private:
|
|||
static void hook_invalidate(struct hwc_procs* procs);
|
||||
static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
|
||||
|
||||
void invalidate();
|
||||
void vsync(int dpy, int64_t timestamp);
|
||||
inline void invalidate();
|
||||
inline void vsync(int dpy, int64_t timestamp);
|
||||
|
||||
sp<SurfaceFlinger> mFlinger;
|
||||
hw_module_t const* mModule;
|
||||
|
@ -101,6 +185,9 @@ private:
|
|||
hwc_display_t mDpy;
|
||||
hwc_surface_t mSur;
|
||||
cb_context mCBContext;
|
||||
EventHandler& mEventHandler;
|
||||
nsecs_t mRefreshPeriod;
|
||||
sp<VSyncThread> mVSyncThread;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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_ */
|
|
@ -38,13 +38,15 @@ namespace android {
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -105,76 +107,89 @@ void EventThread::requestNextVsync(
|
|||
}
|
||||
}
|
||||
|
||||
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<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++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
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);
|
||||
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++) {
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <utils/threads.h>
|
||||
#include <utils/SortedVector.h>
|
||||
|
||||
#include "DisplayHardware/DisplayHardware.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
@ -34,11 +36,10 @@ namespace android {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
class SurfaceFlinger;
|
||||
class DisplayHardware;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class EventThread : public Thread {
|
||||
class EventThread : public Thread, public DisplayHardware::VSyncHandler {
|
||||
class Connection : public BnDisplayEventConnection {
|
||||
public:
|
||||
Connection(const sp<EventThread>& eventThread);
|
||||
|
@ -80,12 +81,13 @@ private:
|
|||
virtual bool threadLoop();
|
||||
virtual status_t readyToRun();
|
||||
virtual void onFirstRef();
|
||||
virtual void onVSyncReceived(int, nsecs_t timestamp);
|
||||
|
||||
void removeDisplayEventConnection(const wp<Connection>& connection);
|
||||
|
||||
// constants
|
||||
sp<SurfaceFlinger> mFlinger;
|
||||
const DisplayHardware& mHw;
|
||||
DisplayHardware& mHw;
|
||||
|
||||
mutable Mutex mLock;
|
||||
mutable Condition mCondition;
|
||||
|
@ -93,6 +95,7 @@ private:
|
|||
// protected by mLock
|
||||
SortedVector< wp<Connection> > mDisplayEventConnections;
|
||||
nsecs_t mLastVSyncTimestamp;
|
||||
nsecs_t mVSyncTimestamp;
|
||||
|
||||
// main thread only
|
||||
size_t mDeliveredEvents;
|
||||
|
|
Loading…
Reference in New Issue