Merge "separate transactions from updates"

This commit is contained in:
Mathias Agopian 2012-02-02 16:28:05 -08:00 committed by Android (Google) Code Review
commit 064b68d1bc
11 changed files with 264 additions and 179 deletions

View File

@ -95,6 +95,8 @@ public:
* should be destroyed and getEvents() shouldn't be called again.
*/
ssize_t getEvents(Event* events, size_t count);
static ssize_t getEvents(const sp<BitTube>& dataChannel,
Event* events, size_t count);
/*
* setVsyncRate() sets the Event::VSync delivery rate. A value of

View File

@ -80,7 +80,13 @@ status_t DisplayEventReceiver::requestNextVsync() {
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
return DisplayEventReceiver::getEvents(mDataChannel, events, count);
}
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));

View File

@ -32,7 +32,6 @@ ifeq ($(TARGET_BOARD_PLATFORM), omap3)
endif
ifeq ($(TARGET_BOARD_PLATFORM), omap4)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
LOCAL_CFLAGS += -DUSE_TRIPLE_BUFFERING=1
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE

View File

@ -55,6 +55,7 @@ Layer::Layer(SurfaceFlinger* flinger,
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentOpacity(true),
mRefreshPending(0),
mFrameLatencyNeeded(false),
mFrameLatencyOffset(0),
mFormat(PIXEL_FORMAT_NONE),
@ -97,12 +98,7 @@ void Layer::onFirstRef()
mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
mSurfaceTexture->setSynchronousMode(true);
#ifdef USE_TRIPLE_BUFFERING
#warning "using triple buffering"
mSurfaceTexture->setBufferCountServer(3);
#else
mSurfaceTexture->setBufferCountServer(2);
#endif
}
Layer::~Layer()
@ -113,7 +109,7 @@ Layer::~Layer()
void Layer::onFrameQueued() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalEvent();
mFlinger->signalLayerUpdate();
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
@ -407,16 +403,37 @@ bool Layer::isCropped() const {
// pageflip handling...
// ----------------------------------------------------------------------------
bool Layer::onPreComposition()
{
// if there was more than one pending update, request a refresh
if (mRefreshPending >= 2) {
mRefreshPending = 0;
return true;
}
mRefreshPending = 0;
return false;
}
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {
// if we've already called updateTexImage() without going through
// a composition step, we have to skip this layer at this point
// because we cannot call updateTeximage() without a corresponding
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending++) {
return;
}
// Capture the old state of the layer for comparisons later
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {
mFlinger->signalEvent();
mFlinger->signalLayerUpdate();
}
if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
@ -519,6 +536,10 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
void Layer::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion)
{
if (mRefreshPending >= 2) {
return;
}
Region dirtyRegion(mPostedDirtyRegion);
if (!dirtyRegion.isEmpty()) {
mPostedDirtyRegion.clear();
@ -552,9 +573,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
snprintf(buffer, SIZE,
" "
"format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
" transform-hint=0x%02x, queued-frames=%d\n",
" transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n",
mFormat, w0, h0, s0,f0,
getTransformHint(), mQueuedFrames);
getTransformHint(), mQueuedFrames, mRefreshPending);
result.append(buffer);

View File

@ -80,6 +80,7 @@ public:
virtual wp<IBinder> getSurfaceTextureBinder() const;
virtual void onLayerDisplayed();
virtual bool onPreComposition();
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
@ -115,14 +116,17 @@ private:
uint32_t mCurrentTransform;
uint32_t mCurrentScalingMode;
bool mCurrentOpacity;
size_t mRefreshPending;
bool mFrameLatencyNeeded;
int mFrameLatencyOffset;
struct Statistics {
Statistics() : timestamp(0), set(0), vsync(0) { }
nsecs_t timestamp; // buffer timestamp
nsecs_t set; // buffer displayed timestamp
nsecs_t vsync; // vsync immediately before set
};
// protected by mLock
Statistics mFrameStats[128];

View File

@ -47,8 +47,7 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
mOrientation(0),
mPlaneOrientation(0),
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
mInvalidate(0)
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
@ -262,23 +261,11 @@ void LayerBase::validateVisibility(const Transform& planeTransform)
mTransformedBounds = tr.makeBounds(w, h);
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
{
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) {
}
void LayerBase::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion)
{
if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
outDirtyRegion.orSelf(visibleRegionScreen);
}
}
void LayerBase::invalidate()
{
if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
mFlinger->signalEvent();
}
const Transform& planeTransform, Region& outDirtyRegion) {
}
void LayerBase::drawRegion(const Region& reg) const

View File

@ -103,8 +103,6 @@ public:
Rect visibleBounds() const;
void drawRegion(const Region& reg) const;
void invalidate();
virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
virtual sp<Layer> getLayer() const { return 0; }
@ -204,9 +202,16 @@ public:
/** called with the state lock when the surface is removed from the
* current list */
virtual void onRemoved() { };
virtual void onRemoved() { }
virtual void onLayerDisplayed() { };
/** called after page-flip
*/
virtual void onLayerDisplayed() { }
/** called before composition.
* returns true if the layer has pending updates.
*/
virtual bool onPreComposition() { return false; }
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
@ -275,10 +280,6 @@ protected:
mutable bool mDebug;
// atomic
volatile int32_t mInvalidate;
public:
// called from class SurfaceFlinger
virtual ~LayerBase();

View File

@ -29,6 +29,7 @@
#include "MessageQueue.h"
#include "EventThread.h"
#include "SurfaceFlinger.h"
namespace android {
@ -48,14 +49,47 @@ void MessageBase::handleMessage(const Message&) {
// ---------------------------------------------------------------------------
void MessageQueue::Handler::signalRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
void MessageQueue::Handler::signalInvalidate() {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
}
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
case REFRESH:
android_atomic_and(~eventMaskRefresh, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
}
}
// ---------------------------------------------------------------------------
MessageQueue::MessageQueue()
: mLooper(new Looper(true)), mWorkPending(0)
{
}
MessageQueue::~MessageQueue() {
}
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
mEventThread = eventThread;
@ -68,25 +102,16 @@ void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case ALOOPER_POLL_WAKE:
case ALOOPER_POLL_CALLBACK:
// callback and/or wake
if (android_atomic_and(0, &mWorkPending)) {
return;
}
continue;
case ALOOPER_POLL_ERROR:
ALOGE("ALOOPER_POLL_ERROR");
case ALOOPER_POLL_TIMEOUT:
// timeout (should not happen)
continue;
case ALOOPER_POLL_ERROR:
ALOGE("ALOOPER_POLL_ERROR");
continue;
default:
// should not happen
ALOGE("Looper::pollOnce() returned unknown status %d", ret);
@ -107,15 +132,12 @@ status_t MessageQueue::postMessage(
return NO_ERROR;
}
void MessageQueue::scheduleWorkASAP() {
if (android_atomic_or(1, &mWorkPending) == 0) {
mLooper->wake();
}
void MessageQueue::invalidate() {
mHandler->signalInvalidate();
}
status_t MessageQueue::invalidate() {
void MessageQueue::refresh() {
mEvents->requestNextVsync();
return NO_ERROR;
}
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
@ -126,10 +148,10 @@ int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
int MessageQueue::eventReceiver(int fd, int events) {
ssize_t n;
DisplayEventReceiver::Event buffer[8];
while ((n = getEvents(buffer, 8)) > 0) {
while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
scheduleWorkASAP();
mHandler->signalRefresh();
break;
}
}
@ -137,24 +159,6 @@ int MessageQueue::eventReceiver(int fd, int events) {
return 1;
}
ssize_t MessageQueue::getEvents(
DisplayEventReceiver::Event* events, size_t count)
{
ssize_t size = mEventTube->read(events, sizeof(events[0])*count);
ALOGE_IF(size<0, "MessageQueue::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).
// returns number of events read
size /= sizeof(events[0]);
}
return size;
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -33,6 +33,7 @@ namespace android {
class IDisplayEventConnection;
class EventThread;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
@ -59,25 +60,48 @@ private:
// ---------------------------------------------------------------------------
class MessageQueue {
class Handler : public MessageHandler {
enum {
eventMaskInvalidate = 0x1,
eventMaskRefresh = 0x2
};
MessageQueue& mQueue;
int32_t mEventMask;
public:
Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
virtual void handleMessage(const Message& message);
void signalRefresh();
void signalInvalidate();
};
friend class Handler;
sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
sp<EventThread> mEventThread;
sp<IDisplayEventConnection> mEvents;
sp<BitTube> mEventTube;
int32_t mWorkPending;
sp<Handler> mHandler;
static int cb_eventReceiver(int fd, int events, void* data);
int eventReceiver(int fd, int events);
ssize_t getEvents(DisplayEventReceiver::Event* events, size_t count);
void scheduleWorkASAP();
public:
enum {
INVALIDATE = 0,
REFRESH = 1,
};
MessageQueue();
~MessageQueue();
void init(const sp<SurfaceFlinger>& flinger);
void setEventThread(const sp<EventThread>& events);
void waitMessage();
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
status_t invalidate();
void invalidate();
void refresh();
};
// ---------------------------------------------------------------------------

View File

@ -125,11 +125,34 @@ void SurfaceFlinger::init()
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
void SurfaceFlinger::onFirstRef()
{
mEventQueue.init(this);
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
}
void SurfaceFlinger::binderDied(const wp<IBinder>& who)
{
// the window manager died on us. prepare its eulogy.
// reset screen orientation
Vector<ComposerState> state;
setTransactionState(state, eOrientationDefault, 0);
// restart the boot-animation
property_set("ctl.start", "bootanim");
}
sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
return mServerHeap;
@ -183,26 +206,6 @@ void SurfaceFlinger::bootFinished()
property_set("ctl.stop", "bootanim");
}
void SurfaceFlinger::binderDied(const wp<IBinder>& who)
{
// the window manager died on us. prepare its eulogy.
// reset screen orientation
Vector<ComposerState> state;
setTransactionState(state, eOrientationDefault, 0);
// restart the boot-animation
property_set("ctl.start", "bootanim");
}
void SurfaceFlinger::onFirstRef()
{
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
static inline uint16_t pack565(int r, int g, int b) {
return (r<<11)|(g<<5)|b;
}
@ -310,34 +313,6 @@ status_t SurfaceFlinger::readyToRun()
return NO_ERROR;
}
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
#pragma mark Events Handler
#endif
void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}
void SurfaceFlinger::signalEvent() {
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(
@ -388,54 +363,93 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
}
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
#pragma mark Main loop
#endif
void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}
void SurfaceFlinger::signalTransaction() {
mEventQueue.invalidate();
}
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue.invalidate();
}
void SurfaceFlinger::signalRefresh() {
mEventQueue.refresh();
}
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::threadLoop()
{
waitForEvent();
// check for transactions
if (CC_UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (CC_UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
// post surfaces (if needed)
handlePageFlip();
if (mDirtyRegion.isEmpty()) {
// nothing new to do.
return true;
}
if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList();
}
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (CC_LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
handleRepaint();
// inform the h/w that we're done compositing
hw.compositionComplete();
postFramebuffer();
} else {
// pretend we did the post
hw.compositionComplete();
}
return true;
}
void SurfaceFlinger::onMessageReceived(int32_t what)
{
switch (what) {
case MessageQueue::INVALIDATE: {
// check for transactions
if (CC_UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (CC_UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
// post surfaces (if needed)
handlePageFlip();
if (!mDirtyRegion.isEmpty()) {
signalRefresh();
}
} break;
case MessageQueue::REFRESH: {
if (!mDirtyRegion.isEmpty()) {
// NOTE: it is mandatory to call hw.compositionComplete()
// after handleRefresh()
handleRefresh();
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList();
}
if (CC_LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
handleRepaint();
// inform the h/w that we're done compositing
hw.compositionComplete();
postFramebuffer();
} else {
// pretend we did the post
hw.compositionComplete();
}
}
} break;
}
}
void SurfaceFlinger::postFramebuffer()
{
// this should never happen. we do the flip anyways so we don't
@ -717,13 +731,13 @@ void SurfaceFlinger::commitTransaction()
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
const Region screenRegion(hw.bounds());
const DisplayHardware& hw = graphicPlane(0).displayHardware();
const Region screenRegion(hw.bounds());
if (visibleRegions) {
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const bool visibleRegions = lockPageFlip(currentLayers);
if (visibleRegions || mVisibleRegionsDirty) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
@ -770,7 +784,7 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
{
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
size_t count = currentLayers.size();
const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
@ -778,6 +792,23 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
}
}
void SurfaceFlinger::handleRefresh()
{
bool needInvalidate = false;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
if (layer->onPreComposition()) {
needInvalidate = true;
}
}
if (needInvalidate) {
signalLayerUpdate();
}
}
void SurfaceFlinger::handleWorkList()
{
mHwWorkListDirty = false;
@ -1175,7 +1206,7 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
{
uint32_t old = android_atomic_or(flags, &mTransactionFlags);
if ((old & flags)==0) { // wake the server up
signalEvent();
signalTransaction();
}
return old;
}
@ -1426,14 +1457,14 @@ void SurfaceFlinger::screenReleased(int dpy)
{
// this may be called by a signal handler, we can't do too much in here
android_atomic_or(eConsoleReleased, &mConsoleSignals);
signalEvent();
signalTransaction();
}
void SurfaceFlinger::screenAcquired(int dpy)
{
// this may be called by a signal handler, we can't do too much in here
android_atomic_or(eConsoleAcquired, &mConsoleSignals);
signalEvent();
signalTransaction();
}
status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
@ -1769,7 +1800,7 @@ void SurfaceFlinger::repaintEverything() {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const Rect bounds(hw.getBounds());
setInvalidateRegion(Region(bounds));
signalEvent();
signalTransaction();
}
void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
@ -2245,7 +2276,7 @@ status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
// make sure to redraw the whole screen when the animation is done
mDirtyRegion.set(hw.bounds());
signalEvent();
signalTransaction();
return NO_ERROR;
}

View File

@ -190,6 +190,8 @@ public:
status_t renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
void onMessageReceived(int32_t what);
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
@ -283,7 +285,10 @@ private:
public: // hack to work around gcc 4.0.3 bug
const GraphicPlane& graphicPlane(int dpy) const;
GraphicPlane& graphicPlane(int dpy);
void signalEvent();
void signalTransaction();
void signalLayerUpdate();
void signalRefresh();
void repaintEverything();
private:
@ -300,6 +305,7 @@ private:
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRefresh();
void handleWorkList();
void handleRepaint();
void postFramebuffer();