Camera: Handle release fence when syncing preview to display
If release fence is enabled by the HAL, the time when a frame becomes
available isn't necessarily the time when processCaptureResult() is
called. The fence may signal sometime after processCaptureResult().
Support this use case by checking the reference frame's fence signal
time and update the captureToPresentOffset.
Test: Vendor testing
Bug: 276280239
Change-Id: I5278c2e2f9961af2cf667235254ad32eea126895
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index f2a62fa..a387064 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -486,7 +486,7 @@
bufferDeferred = true;
} else {
nsecs_t presentTime = mSyncToDisplay ?
- syncTimestampToDisplayLocked(captureTime) : captureTime;
+ syncTimestampToDisplayLocked(captureTime, releaseFence->dup()) : captureTime;
setTransform(transform, true/*mayChangeMirror*/);
res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
@@ -1410,7 +1410,7 @@
}
}
-nsecs_t Camera3OutputStream::syncTimestampToDisplayLocked(nsecs_t t) {
+nsecs_t Camera3OutputStream::syncTimestampToDisplayLocked(nsecs_t t, int releaseFence) {
nsecs_t currentTime = systemTime();
if (!mFixedFps) {
mLastCaptureTime = t;
@@ -1453,6 +1453,17 @@
mLastCaptureTime = t;
mLastPresentTime = presentT;
+ // If releaseFence is available, store the fence to check signal
+ // time later.
+ mRefVsyncData = vsyncEventData;
+ mReferenceCaptureTime = t;
+ mReferenceArrivalTime = currentTime;
+ if (releaseFence != -1) {
+ mReferenceFrameFence = new Fence(releaseFence);
+ } else {
+ mFenceSignalOffset = 0;
+ }
+
// Move the expected presentation time back by 1/3 of frame interval to
// mitigate the time drift. Due to time drift, if we directly use the
// expected presentation time, often times 2 expected presentation time
@@ -1462,6 +1473,36 @@
}
}
+ // If there is a reference frame release fence, get the signal time and
+ // update the captureToPresentOffset.
+ if (mReferenceFrameFence != nullptr) {
+ mFenceSignalOffset = 0;
+ nsecs_t signalTime = mReferenceFrameFence->getSignalTime();
+ // Now that the fence has signaled, recalculate the offsets based on
+ // the timeline which was actually latched
+ if (signalTime != INT64_MAX) {
+ for (size_t i = 0; i < mRefVsyncData.frameTimelinesLength; i++) {
+ const auto& timeline = mRefVsyncData.frameTimelines[i];
+ if (timeline.deadlineTimestamp >= signalTime) {
+ nsecs_t originalOffset = mCaptureToPresentOffset;
+ mCaptureToPresentOffset = timeline.expectedPresentationTime
+ - mReferenceCaptureTime;
+ mLastPresentTime = timeline.expectedPresentationTime;
+ mFenceSignalOffset = signalTime > mReferenceArrivalTime ?
+ signalTime - mReferenceArrivalTime : 0;
+
+ ALOGV("%s: Last deadline %" PRId64 " signalTime %" PRId64
+ " original offset %" PRId64 " new offset %" PRId64
+ " fencesignal offset %" PRId64, __FUNCTION__,
+ timeline.deadlineTimestamp, signalTime, originalOffset,
+ mCaptureToPresentOffset, mFenceSignalOffset);
+ break;
+ }
+ }
+ mReferenceFrameFence.clear();
+ }
+ }
+
nsecs_t idealPresentT = t + mCaptureToPresentOffset;
nsecs_t expectedPresentT = mLastPresentTime;
nsecs_t minDiff = INT64_MAX;
@@ -1505,6 +1546,7 @@
// Find best timestamp in the vsync timelines:
// - Only use at most kMaxTimelines timelines to avoid long latency
+ // - Add an extra timeline if display fence is used
// - closest to the ideal presentation time,
// - deadline timestamp is greater than the current time, and
// - For fixed FPS, if the capture interval doesn't deviate too much from refresh interval,
@@ -1513,7 +1555,9 @@
// - For variable FPS, or if the capture interval deviates from refresh
// interval for more than 5%, find a presentation time closest to the
// (lastPresentationTime + captureToPresentOffset) instead.
- int maxTimelines = std::min(kMaxTimelines, (int)vsyncEventData.frameTimelinesLength);
+ int fenceAdjustment = (mFenceSignalOffset > 0) ? 1 : 0;
+ int maxTimelines = std::min(kMaxTimelines + fenceAdjustment,
+ (int)vsyncEventData.frameTimelinesLength);
float biasForShortDelay = 1.0f;
for (int i = 0; i < maxTimelines; i ++) {
const auto& vsyncTime = vsyncEventData.frameTimelines[i];
@@ -1524,7 +1568,7 @@
biasForShortDelay = 1.0 - 2.0 * i / (maxTimelines - 1);
}
if (std::abs(vsyncTime.expectedPresentationTime - idealPresentT) < minDiff &&
- vsyncTime.deadlineTimestamp >= currentTime &&
+ vsyncTime.deadlineTimestamp >= currentTime + mFenceSignalOffset &&
((!cameraDisplayInSync && vsyncTime.expectedPresentationTime > minPresentT) ||
(cameraDisplayInSync && vsyncTime.expectedPresentationTime >
mLastPresentTime + minInterval +