Plumbing for getting FenceTracker timestamps
Change-Id: I1ebee9e42e28658bd3a2b161fdaabb7da756d8f3
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index ccbb5a2..6de98f5 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,6 +61,15 @@
}
}
+bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != NULL) {
+ return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ }
+ return false;
+}
+
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 65f8255..ac7ac07 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1401,6 +1401,22 @@
return NO_ERROR;
}
+bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ ATRACE_CALL();
+ BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
+ sp<IConsumerListener> listener;
+
+ {
+ Mutex::Autolock lock(mCore->mMutex);
+ listener = mCore->mConsumerListener;
+ }
+ if (listener != NULL) {
+ return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ }
+ return false;
+}
+
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index cab7dc3..9a06011 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -31,6 +31,7 @@
ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
ON_BUFFER_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
+ GET_FRAME_TIMESTAMPS
};
class BpConsumerListener : public BpInterface<IConsumerListener>
@@ -60,6 +61,42 @@
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IConsumerListener::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write token: %d", result);
+ return false;
+ }
+ result = data.writeUint64(frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write: %d", result);
+ return false;
+ }
+ result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to transact: %d", result);
+ return false;
+ }
+ bool found = false;
+ result = reply.readBool(&found);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read: %d", result);
+ return false;
+ }
+ if (found) {
+ result = reply.read(*outTimestamps);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read timestamps: %d",
+ result);
+ return false;
+ }
+ }
+ return found;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -88,6 +125,30 @@
CHECK_INTERFACE(IConsumerListener, data, reply);
onSidebandStreamChanged();
return NO_ERROR; }
+ case GET_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(IConsumerListener, data, reply);
+ uint64_t frameNumber = 0;
+ status_t result = data.readUint64(&frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to read: %d", result);
+ return result;
+ }
+ FrameTimestamps timestamps;
+ bool found = getFrameTimestamps(frameNumber, ×tamps);
+ result = reply->writeBool(found);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write: %d", result);
+ return result;
+ }
+ if (found) {
+ result = reply->write(timestamps);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write timestamps: %d", result);
+ return result;
+ }
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 2c48d83..9317eff 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -55,6 +55,7 @@
SET_AUTO_REFRESH,
SET_DEQUEUE_TIMEOUT,
GET_LAST_QUEUED_BUFFER,
+ GET_FRAME_TIMESTAMPS
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -418,6 +419,42 @@
*outFence = fence;
return result;
}
+
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) const {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write token: %d", result);
+ return false;
+ }
+ result = data.writeUint64(frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to write: %d", result);
+ return false;
+ }
+ result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to transact: %d", result);
+ return false;
+ }
+ bool found = false;
+ result = reply.readBool(&found);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read: %d", result);
+ return false;
+ }
+ if (found) {
+ result = reply.read(*outTimestamps);
+ if (result != NO_ERROR) {
+ ALOGE("getFrameTimestamps failed to read timestamps: %d",
+ result);
+ return false;
+ }
+ }
+ return found;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -659,6 +696,30 @@
}
return NO_ERROR;
}
+ case GET_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ uint64_t frameNumber = 0;
+ status_t result = data.readUint64(&frameNumber);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to read: %d", result);
+ return result;
+ }
+ FrameTimestamps timestamps;
+ bool found = getFrameTimestamps(frameNumber, ×tamps);
+ result = reply->writeBool(found);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write: %d", result);
+ return result;
+ }
+ if (found) {
+ result = reply->write(timestamps);
+ if (result != NO_ERROR) {
+ ALOGE("onTransact failed to write timestamps: %d", result);
+ return result;
+ }
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6811269..85c194d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -133,6 +133,39 @@
outTransformMatrix);
}
+bool Surface::getFrameTimestamps(uint64_t frameNumber, nsecs_t* outPostedTime,
+ nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime,
+ nsecs_t* outGlCompositionDoneTime, nsecs_t* outDisplayRetireTime,
+ nsecs_t* outReleaseTime) {
+ ATRACE_CALL();
+
+ FrameTimestamps timestamps;
+ bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
+ ×tamps);
+ if (found) {
+ if (outPostedTime) {
+ *outPostedTime = timestamps.postedTime;
+ }
+ if (outAcquireTime) {
+ *outAcquireTime = timestamps.acquireTime;
+ }
+ if (outRefreshStartTime) {
+ *outRefreshStartTime = timestamps.refreshStartTime;
+ }
+ if (outGlCompositionDoneTime) {
+ *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+ }
+ if (outDisplayRetireTime) {
+ *outDisplayRetireTime = timestamps.displayRetireTime;
+ }
+ if (outReleaseTime) {
+ *outReleaseTime = timestamps.releaseTime;
+ }
+ return true;
+ }
+ return false;
+}
+
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
return c->setSwapInterval(interval);
@@ -614,6 +647,9 @@
case NATIVE_WINDOW_SET_AUTO_REFRESH:
res = dispatchSetAutoRefresh(args);
break;
+ case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
+ res = dispatchGetFrameTimestamps(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -734,6 +770,20 @@
return setAutoRefresh(autoRefresh);
}
+int Surface::dispatchGetFrameTimestamps(va_list args) {
+ uint32_t framesAgo = va_arg(args, uint32_t);
+ nsecs_t* outPostedTime = va_arg(args, int64_t*);
+ nsecs_t* outAcquireTime = va_arg(args, int64_t*);
+ nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
+ nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
+ nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+ nsecs_t* outReleaseTime = va_arg(args, int64_t*);
+ bool ret = getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
+ outPostedTime, outAcquireTime, outRefreshStartTime,
+ outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+ return ret ? NO_ERROR : BAD_VALUE;
+}
+
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);