fix another bug where screenshots could end-up all black

SF transactions were always handled on VSYNC which allowed
the screenshot to sneak-in between closing the transaction
and vsync (before it's latched), resulting in a screenshot
with the previous state.

we now always force transactions to happen immediately
before screenhots.

Bug: 7552304
Change-Id: I0afc86b7e8366173daff5b9988bbb4d2a0f43860
This commit is contained in:
Mathias Agopian 2013-04-10 16:27:17 -07:00
parent 1df59c93fe
commit 9eb1f0558b
3 changed files with 37 additions and 4 deletions

View File

@ -61,6 +61,12 @@ void MessageQueue::Handler::dispatchInvalidate() {
} }
} }
void MessageQueue::Handler::dispatchTransaction() {
if ((android_atomic_or(eventMaskTransaction, &mEventMask) & eventMaskTransaction) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::TRANSACTION));
}
}
void MessageQueue::Handler::handleMessage(const Message& message) { void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) { switch (message.what) {
case INVALIDATE: case INVALIDATE:
@ -71,6 +77,10 @@ void MessageQueue::Handler::handleMessage(const Message& message) {
android_atomic_and(~eventMaskRefresh, &mEventMask); android_atomic_and(~eventMaskRefresh, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what); mQueue.mFlinger->onMessageReceived(message.what);
break; break;
case TRANSACTION:
android_atomic_and(~eventMaskTransaction, &mEventMask);
mQueue.mFlinger->onMessageReceived(message.what);
break;
} }
} }
@ -132,6 +142,7 @@ status_t MessageQueue::postMessage(
return NO_ERROR; return NO_ERROR;
} }
/* when INVALIDATE_ON_VSYNC is set SF only processes /* when INVALIDATE_ON_VSYNC is set SF only processes
* buffer updates on VSYNC and performs a refresh immediately * buffer updates on VSYNC and performs a refresh immediately
* after. * after.
@ -143,6 +154,10 @@ status_t MessageQueue::postMessage(
*/ */
#define INVALIDATE_ON_VSYNC 1 #define INVALIDATE_ON_VSYNC 1
void MessageQueue::invalidateTransactionNow() {
mHandler->dispatchTransaction();
}
void MessageQueue::invalidate() { void MessageQueue::invalidate() {
#if INVALIDATE_ON_VSYNC #if INVALIDATE_ON_VSYNC
mEvents->requestNextVsync(); mEvents->requestNextVsync();

View File

@ -62,8 +62,9 @@ private:
class MessageQueue { class MessageQueue {
class Handler : public MessageHandler { class Handler : public MessageHandler {
enum { enum {
eventMaskInvalidate = 0x1, eventMaskInvalidate = 0x1,
eventMaskRefresh = 0x2 eventMaskRefresh = 0x2,
eventMaskTransaction = 0x4
}; };
MessageQueue& mQueue; MessageQueue& mQueue;
int32_t mEventMask; int32_t mEventMask;
@ -72,6 +73,7 @@ class MessageQueue {
virtual void handleMessage(const Message& message); virtual void handleMessage(const Message& message);
void dispatchRefresh(); void dispatchRefresh();
void dispatchInvalidate(); void dispatchInvalidate();
void dispatchTransaction();
}; };
friend class Handler; friend class Handler;
@ -89,8 +91,9 @@ class MessageQueue {
public: public:
enum { enum {
INVALIDATE = 0, INVALIDATE = 0,
REFRESH = 1, REFRESH = 1,
TRANSACTION = 2
}; };
MessageQueue(); MessageQueue();
@ -100,8 +103,13 @@ public:
void waitMessage(); void waitMessage();
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0); status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
// sends INVALIDATE message at next VSYNC
void invalidate(); void invalidate();
// sends REFRESH message at next VSYNC
void refresh(); void refresh();
// sends TRANSACTION message immediately
void invalidateTransactionNow();
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -744,6 +744,9 @@ void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
void SurfaceFlinger::onMessageReceived(int32_t what) { void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL(); ATRACE_CALL();
switch (what) { switch (what) {
case MessageQueue::TRANSACTION:
handleMessageTransaction();
break;
case MessageQueue::INVALIDATE: case MessageQueue::INVALIDATE:
handleMessageTransaction(); handleMessageTransaction();
handleMessageInvalidate(); handleMessageInvalidate();
@ -2626,6 +2629,13 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
} }
}; };
// make sure to process transactions before screenshots -- a transaction
// might already be pending but scheduled for VSYNC; this guarantees we
// will handle it before the screenshot. When VSYNC finally arrives
// the scheduled transaction will be a no-op. If no transactions are
// scheduled at this time, this will end-up being a no-op as well.
mEventQueue.invalidateTransactionNow();
sp<MessageBase> msg = new MessageCaptureScreen(this, sp<MessageBase> msg = new MessageCaptureScreen(this,
display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
isCpuConsumer); isCpuConsumer);