Merge "Replace JNI primitive array critical calls with non-critical ones." into mnc-dev
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 0f42613..cde302f 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -47,7 +47,7 @@
// returned. The presentation time is in nanoseconds, and the time base
// is CLOCK_MONOTONIC.
virtual status_t acquireBuffer(BufferItem* outBuffer,
- nsecs_t expectedPresent);
+ nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;
// See IGraphicBufferConsumer::detachBuffer
virtual status_t detachBuffer(int slot);
@@ -148,9 +148,6 @@
// Retrieve the sideband buffer stream, if any.
virtual sp<NativeHandle> getSidebandStream() const;
- // See IGraphicBufferConsumer::setShadowQueueSize
- virtual void setShadowQueueSize(size_t size);
-
// dump our state in a String
virtual void dump(String8& result, const char* prefix) const;
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index a22015c..d7686ec 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -275,12 +275,6 @@
// buffer as the number of frames that have elapsed since it was last queued
uint64_t mBufferAge;
- // mConsumerHasShadowQueue determines if acquireBuffer should be more
- // cautious about dropping buffers so that it always returns a buffer that
- // is represented in the consumer's shadow queue.
- bool mConsumerHasShadowQueue;
- size_t mConsumerShadowQueueSize;
-
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 5be3ffb..f46bf01 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,8 @@
// initialization that must take place the first time a buffer is assigned
// to a slot. If it is overridden the derived class's implementation must
// call ConsumerBase::acquireBufferLocked.
- virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+ virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0);
// releaseBufferLocked relinquishes control over a buffer, returning that
// control to the BufferQueue.
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 4912580..c35c7be 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -241,7 +241,8 @@
// acquireBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase behavior.
- virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+ virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) override;
// releaseBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase.
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 0be09a2..6363a3a 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -69,6 +69,12 @@
// returned. The presentation time is in nanoseconds, and the time base
// is CLOCK_MONOTONIC.
//
+ // If maxFrameNumber is non-zero, it indicates that acquireBuffer should
+ // only return a buffer with a frame number less than or equal to
+ // maxFrameNumber. If no such frame is available (such as when a buffer has
+ // been replaced but the consumer has not received the onFrameReplaced
+ // callback), then PRESENT_LATER will be returned.
+ //
// Return of NO_ERROR means the operation completed as normal.
//
// Return of a positive value means the operation could not be completed
@@ -78,7 +84,8 @@
//
// Return of a negative value means an error has occurred:
// * INVALID_OPERATION - too many buffers have been acquired
- virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
+ virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) = 0;
// detachBuffer attempts to remove all ownership of the buffer in the given
// slot from the buffer queue. If this call succeeds, the slot will be
@@ -248,11 +255,6 @@
// Retrieve the sideband buffer stream, if any.
virtual sp<NativeHandle> getSidebandStream() const = 0;
- // setShadowQueueSize notifies the BufferQueue that the consumer is
- // shadowing its queue and allows it to limit the number of buffers it is
- // permitted to drop during acquire so as to not get out of sync.
- virtual void setShadowQueueSize(size_t size) = 0;
-
// dump state into a string
virtual void dump(String8& result, const char* prefix) const = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 1b197a4..015866b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1347,6 +1347,10 @@
if (err != NO_ERROR) return 0;
native_handle* h = native_handle_create(numFds, numInts);
+ if (!h) {
+ return 0;
+ }
+
for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
h->data[i] = dup(readFileDescriptor());
if (h->data[i] < 0) err = BAD_VALUE;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 336ddb6..4174676 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,7 +36,7 @@
BufferQueueConsumer::~BufferQueueConsumer() {}
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
- nsecs_t expectedPresent) {
+ nsecs_t expectedPresent, uint64_t maxFrameNumber) {
ATRACE_CALL();
Mutex::Autolock lock(mCore->mMutex);
@@ -89,17 +89,12 @@
// the timestamps are being auto-generated by Surface. If the app isn't
// generating timestamps explicitly, it probably doesn't want frames to
// be discarded based on them.
- //
- // If the consumer is shadowing our queue, we also make sure that we
- // don't drop so many buffers that the consumer hasn't received the
- // onFrameAvailable callback for the buffer it acquires. That is, we
- // want the buffer we return to be in the consumer's shadow queue.
- size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ?
- mCore->mConsumerShadowQueueSize - 1 : 0;
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
- if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) {
- BQ_LOGV("acquireBuffer: no droppable buffers in consumer's"
- " shadow queue, continuing");
+ const BufferItem& bufferItem(mCore->mQueue[1]);
+
+ // If dropping entry[0] would leave us with a buffer that the
+ // consumer is not yet ready for, don't drop it.
+ if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
break;
}
@@ -112,7 +107,6 @@
//
// We may want to add an additional criterion: don't drop the
// earlier buffer if entry[1]'s fence hasn't signaled yet.
- const BufferItem& bufferItem(mCore->mQueue[1]);
nsecs_t desiredPresent = bufferItem.mTimestamp;
if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
desiredPresent > expectedPresent) {
@@ -137,18 +131,22 @@
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
- --droppableBuffers;
}
- // See if the front buffer is due
+ // See if the front buffer is ready to be acquired
nsecs_t desiredPresent = front->mTimestamp;
- if (desiredPresent > expectedPresent &&
- desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+ bool bufferIsDue = desiredPresent <= expectedPresent ||
+ desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+ bool consumerIsReady = maxFrameNumber > 0 ?
+ front->mFrameNumber <= maxFrameNumber : true;
+ if (!bufferIsDue || !consumerIsReady) {
BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
- " (%" PRId64 ") now=%" PRId64,
+ " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
+ " consumer=%" PRIu64,
desiredPresent, expectedPresent,
desiredPresent - expectedPresent,
- systemTime(CLOCK_MONOTONIC));
+ systemTime(CLOCK_MONOTONIC),
+ front->mFrameNumber, maxFrameNumber);
return PRESENT_LATER;
}
@@ -553,14 +551,6 @@
return mCore->mSidebandStream;
}
-void BufferQueueConsumer::setShadowQueueSize(size_t size) {
- ATRACE_CALL();
- BQ_LOGV("setShadowQueueSize: %zu", size);
- Mutex::Autolock lock(mCore->mMutex);
- mCore->mConsumerHasShadowQueue = true;
- mCore->mConsumerShadowQueueSize = size;
-}
-
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
mCore->dump(result, prefix);
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 37171ed..e784644 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -71,9 +71,7 @@
mIsAllocating(false),
mIsAllocatingCondition(),
mAllowAllocation(true),
- mBufferAge(0),
- mConsumerHasShadowQueue(false),
- mConsumerShadowQueueSize(0)
+ mBufferAge(0)
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 7251d36..e318484 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -871,6 +871,7 @@
mCore->mBufferHasBeenQueued = false;
mCore->mDequeueBufferCannotBlock =
mCore->mConsumerControlledByApp && producerControlledByApp;
+ mCore->mAllowAllocation = true;
return status;
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index aa9443a..072ab44 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -211,8 +211,8 @@
}
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
- nsecs_t presentWhen) {
- status_t err = mConsumer->acquireBuffer(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 96c0841..9fcac2d 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -344,8 +344,9 @@
}
status_t GLConsumer::acquireBufferLocked(BufferItem *item,
- nsecs_t presentWhen) {
- status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
+ maxFrameNumber);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 480dfb6..b86f4c5 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -52,7 +52,6 @@
SET_CONSUMER_USAGE_BITS,
SET_TRANSFORM_HINT,
GET_SIDEBAND_STREAM,
- SET_SHADOW_QUEUE_SIZE,
DUMP,
};
@@ -67,10 +66,12 @@
virtual ~BpGraphicBufferConsumer();
- virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+ virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen,
+ uint64_t maxFrameNumber) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
data.writeInt64(presentWhen);
+ data.writeUint64(maxFrameNumber);
status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -270,17 +271,6 @@
return stream;
}
- virtual void setShadowQueueSize(size_t size) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
- data.writeInt64(static_cast<int64_t>(size));
- status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("setShadowQueueSize failed (%d)", result);
- return;
- }
- }
-
virtual void dump(String8& result, const char* prefix) const {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -307,7 +297,8 @@
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
BufferItem item;
int64_t presentWhen = data.readInt64();
- status_t result = acquireBuffer(&item, presentWhen);
+ uint64_t maxFrameNumber = data.readUint64();
+ status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber);
status_t err = reply->write(item);
if (err) return err;
reply->writeInt32(result);
@@ -435,12 +426,6 @@
}
return NO_ERROR;
}
- case SET_SHADOW_QUEUE_SIZE: {
- CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- size_t size = static_cast<size_t>(data.readInt64());
- setShadowQueueSize(size);
- return NO_ERROR;
- }
case DUMP: {
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
String8 result = data.readString8();
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8709692..2888785 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -73,6 +73,13 @@
// external stylus.
static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+// Maximum amount of time to wait on touch data before pushing out new pressure data.
+static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+
+// Artificial latency on synthetic events created from stylus data without corresponding touch
+// data.
+static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
// --- Static Functions ---
template<typename T>
@@ -2827,7 +2834,7 @@
toString(mExternalStylusConnected));
dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
- mExternalStylusDataTimeout);
+ mExternalStylusFusionTimeout);
dump.append(INDENT3 "External Stylus State:\n");
dumpStylusState(dump, mExternalStylusState);
@@ -3836,10 +3843,15 @@
void TouchInputMapper::resetExternalStylus() {
mExternalStylusState.clear();
mExternalStylusId = -1;
- mExternalStylusDataTimeout = LLONG_MAX;
+ mExternalStylusFusionTimeout = LLONG_MAX;
mExternalStylusDataPending = false;
}
+void TouchInputMapper::clearStylusDataPendingFlags() {
+ mExternalStylusDataPending = false;
+ mExternalStylusFusionTimeout = LLONG_MAX;
+}
+
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
@@ -3915,19 +3927,30 @@
}
// All ready to go.
- mExternalStylusDataPending = false;
+ clearStylusDataPendingFlags();
mCurrentRawState.copyFrom(next);
+ if (mCurrentRawState.when < mLastRawState.when) {
+ mCurrentRawState.when = mLastRawState.when;
+ }
cookAndDispatch(mCurrentRawState.when);
}
if (count != 0) {
mRawStatesPending.removeItemsAt(0, count);
}
- // TODO: If we still have pending stylus data that hasn't been mapped to a touch yet
- // then set a timeout to synthesize a new touch event with the new data. Otherwise
- // we will lose button and pressure information while the touch is stationary.
if (mExternalStylusDataPending) {
- ALOGD("STYLUS TODO: Wiggle wiggle wiggle.");
+ if (timeout) {
+ nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
+ clearStylusDataPendingFlags();
+ mCurrentRawState.copyFrom(mLastRawState);
+#if DEBUG_STYLUS_FUSION
+ ALOGD("Timeout expired, synthesizing event with new stylus data");
+#endif
+ cookAndDispatch(when);
+ } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+ }
}
}
@@ -4053,14 +4076,20 @@
}
void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
- CookedPointerData& cpd = mCurrentCookedState.cookedPointerData;
- if (mExternalStylusId != -1 && cpd.isTouching(mExternalStylusId)) {
- if (mExternalStylusState.pressure != 0.0f) {
- PointerCoords& coords = cpd.editPointerCoordsWithId(mExternalStylusId);
- coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mExternalStylusState.pressure);
- }
+ CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
+ const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
- PointerProperties& properties = cpd.editPointerPropertiesWithId(mExternalStylusId);
+ if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
+ float pressure = mExternalStylusState.pressure;
+ if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
+ const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
+ pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ }
+ PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+
+ PointerProperties& properties =
+ currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
properties.toolType = mExternalStylusState.toolType;
}
@@ -4086,15 +4115,14 @@
#endif
resetExternalStylus();
} else {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mExternalStylusDataTimeout == LLONG_MAX) {
- mExternalStylusDataTimeout = now + EXTERNAL_STYLUS_DATA_TIMEOUT;
+ if (mExternalStylusFusionTimeout == LLONG_MAX) {
+ mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
}
#if DEBUG_STYLUS_FUSION
ALOGD("No stylus data but stylus is connected, requesting timeout "
- "(%" PRId64 "ms)", mExternalStylusDataTimeout);
+ "(%" PRId64 "ms)", mExternalStylusFusionTimeout);
#endif
- getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout);
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
return true;
}
}
@@ -4117,22 +4145,20 @@
dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
}
} else if (mDeviceMode == DEVICE_MODE_DIRECT) {
- if (mExternalStylusDataTimeout < when) {
- mExternalStylusDataTimeout = LLONG_MAX;
+ if (mExternalStylusFusionTimeout < when) {
processRawTouches(true /*timeout*/);
- } else if (mExternalStylusDataTimeout != LLONG_MAX) {
- getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout);
+ } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
+ getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
}
}
}
void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
mExternalStylusState.copyFrom(state);
- if (mExternalStylusId != -1 || mExternalStylusDataTimeout != LLONG_MAX) {
+ if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
// We're either in the middle of a fused stream of data or we're waiting on data before
// dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
// data.
- mExternalStylusDataTimeout = LLONG_MAX;
mExternalStylusDataPending = true;
processRawTouches(false /*timeout*/);
}
@@ -4310,7 +4336,7 @@
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
- if (moveNeeded) {
+ if (moveNeeded && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 451a20f..ae090c1 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -881,11 +881,11 @@
return pointerProperties[idToIndex[id]];
}
- inline bool isHovering(uint32_t pointerIndex) {
+ inline bool isHovering(uint32_t pointerIndex) const {
return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
}
- inline bool isTouching(uint32_t pointerIndex) {
+ inline bool isTouching(uint32_t pointerIndex) const {
return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
}
};
@@ -1456,7 +1456,7 @@
// State provided by an external stylus
StylusState mExternalStylusState;
int64_t mExternalStylusId;
- nsecs_t mExternalStylusDataTimeout;
+ nsecs_t mExternalStylusFusionTimeout;
bool mExternalStylusDataPending;
// True if we sent a HOVER_ENTER event.
@@ -1781,6 +1781,7 @@
VelocityControl mWheelYVelocityControl;
void resetExternalStylus();
+ void clearStylusDataPendingFlags();
void sync(nsecs_t when);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7b104c3..2b733e9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,11 @@
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client),
- mPotentialCursor(false)
+ mPotentialCursor(false),
+ mQueueItemLock(),
+ mQueueItemCondition(),
+ mQueueItems(),
+ mLastFrameNumberReceived(0)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -127,10 +131,6 @@
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
- // Set the shadow queue size to 0 to notify the BufferQueue that we are
- // shadowing it
- mSurfaceFlingerConsumer->setShadowQueueSize(0);
-
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
@@ -167,9 +167,28 @@
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
+
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
mQueueItems.push_back(item);
- mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
mFlinger->signalLayerUpdate();
@@ -177,11 +196,25 @@
void Layer::onFrameReplaced(const BufferItem& item) {
Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
if (mQueueItems.empty()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
mQueueItems.editItemAt(0) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
void Layer::onSidebandStreamChanged() {
@@ -1261,8 +1294,14 @@
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0);
+ uint64_t maxFrameNumber = 0;
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ maxFrameNumber = mLastFrameNumberReceived;
+ }
+
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync);
+ mFlinger->mPrimaryDispSync, maxFrameNumber);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
@@ -1272,12 +1311,7 @@
// If the buffer has been rejected, remove it from the shadow queue
// and return early
Mutex::Autolock lock(mQueueItemLock);
-
- // Update the BufferQueue with the new shadow queue size after
- // dropping this item
mQueueItems.removeAt(0);
- mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
-
android_atomic_dec(&mQueuedFrames);
return outDirtyRegion;
}
@@ -1294,10 +1328,7 @@
android_atomic_dec(&mQueuedFrames);
}
- // Update the BufferQueue with our new shadow queue size, since we
- // have removed at least one item
mQueueItems.removeAt(0);
- mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0b4c640..947da85 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -416,7 +416,9 @@
// Local copy of the queued contents of the incoming BufferQueue
mutable Mutex mQueueItemLock;
+ Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
+ uint64_t mLastFrameNumberReceived;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index a9a2958..ed1f31b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync)
+ const DispSync& dispSync, uint64_t maxFrameNumber)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -54,7 +54,8 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
+ err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
+ maxFrameNumber);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -104,8 +105,9 @@
}
status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
- nsecs_t presentWhen) {
- status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
+ maxFrameNumber);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
mSurfaceDamage = item->mSurfaceDamage;
@@ -125,10 +127,6 @@
return mConsumer->getSidebandStream();
}
-void SurfaceFlingerConsumer::setShadowQueueSize(size_t size) {
- mConsumer->setShadowQueueSize(size);
-}
-
// We need to determine the time when a buffer acquired now will be
// displayed. This can be calculated:
// time when previous buffer's actual-present fence was signaled
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index a90a8b9..779e5b7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -49,13 +49,15 @@
virtual ~BufferRejecter() { }
};
- virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+ virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) override;
// This version of updateTexImage() takes a functor that may be used to
// reject the newly acquired buffer. Unlike the GLConsumer version,
// this does not guarantee that the buffer has been bound to the GL
// texture.
- status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
+ status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+ uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
@@ -70,9 +72,6 @@
sp<NativeHandle> getSidebandStream() const;
- // See IGraphicBufferConsumer::setShadowQueueSize
- void setShadowQueueSize(size_t size);
-
nsecs_t computeExpectedPresent(const DispSync& dispSync);
private: