Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe8a2a32 authored by Shuzhen Wang's avatar Shuzhen Wang
Browse files

Camera: Narrow down cases preview spacer is used

HW_TEXTURE usage flag may be used for ImageReader. Do not treat the
surface as SurfaceTexture if the surface has CPU read flag at the
same time.

In addition:
- Only enable preview spacer if timestamp base is DEFAULT,
- Use readoutTimestamp for re-spacing.
- Remove the system property to disable frame spacing.

Test: Camera CTS, Observe smoother GCA photo preview
Bug: 195025014
Change-Id: I40a3b1acac44ed8a474aad94b77aee8f7399eb31
parent 96ae46c5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -89,9 +89,10 @@ void Camera3IOStreamBase::dump(int fd, const Vector<String16> &args) const {
    if (strlen(camera_stream::physical_camera_id) > 0) {
        lines.appendFormat("      Physical camera id: %s\n", camera_stream::physical_camera_id);
    }
    lines.appendFormat("      Dynamic Range Profile: 0x%" PRIx64,
    lines.appendFormat("      Dynamic Range Profile: 0x%" PRIx64 "\n",
            camera_stream::dynamic_range_profile);
    lines.appendFormat("      Stream use case: %" PRId64 "\n", camera_stream::use_case);
    lines.appendFormat("      Timestamp base: %d\n", getTimestampBase());
    lines.appendFormat("      Frames produced: %d, last timestamp: %" PRId64 " ns\n",
            mFrameCount, mLastTimestamp);
    lines.appendFormat("      Total buffers: %zu, currently dequeued: %zu\n",
+21 −5
Original line number Diff line number Diff line
@@ -466,8 +466,10 @@ status_t Camera3OutputStream::returnBufferCheckedLocked(
        nsecs_t captureTime = (mUseReadoutTime && readoutTimestamp != 0 ?
                readoutTimestamp : timestamp) - mTimestampOffset;
        if (mPreviewFrameSpacer != nullptr) {
            res = mPreviewFrameSpacer->queuePreviewBuffer(captureTime, transform,
                    anwBuffer, anwReleaseFence);
            nsecs_t readoutTime = (readoutTimestamp != 0 ? readoutTimestamp : timestamp)
                    - mTimestampOffset;
            res = mPreviewFrameSpacer->queuePreviewBuffer(captureTime, readoutTime,
                    transform, anwBuffer, anwReleaseFence);
            if (res != OK) {
                ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
                        __FUNCTION__, mId, strerror(-res), res);
@@ -684,12 +686,15 @@ status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowPreviewResp
        bool forceChoreographer = (timestampBase ==
                OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
        bool defaultToChoreographer = (isDefaultTimeBase &&
                isConsumedByHWComposer() &&
                !property_get_bool("camera.disable_preview_scheduler", false));
                isConsumedByHWComposer());
        bool defaultToSpacer = (isDefaultTimeBase &&
                isConsumedByHWTexture() &&
                !isConsumedByCPU() &&
                !isVideoStream());
        if (forceChoreographer || defaultToChoreographer) {
            mSyncToDisplay = true;
            mTotalBufferCount += kDisplaySyncExtraBuffer;
        } else if (isConsumedByHWTexture() && !isVideoStream()) {
        } else if (defaultToSpacer) {
            mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
            mTotalBufferCount ++;
            res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
@@ -1268,6 +1273,17 @@ bool Camera3OutputStream::isConsumedByHWTexture() const {
    return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
}

bool Camera3OutputStream::isConsumedByCPU() const {
    uint64_t usage = 0;
    status_t res = getEndpointUsage(&usage);
    if (res != OK) {
        ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
        return false;
    }

    return (usage & GRALLOC_USAGE_SW_READ_MASK) != 0;
}

void Camera3OutputStream::dumpImageToDisk(nsecs_t timestamp,
        ANativeWindowBuffer* anwBuffer, int fence) {
    // Deriver output file name
+5 −0
Original line number Diff line number Diff line
@@ -159,6 +159,11 @@ class Camera3OutputStream :
     */
    bool isConsumedByHWTexture() const;

    /**
     * Return if this output stream is consumed by CPU.
     */
    bool isConsumedByCPU() const;

    /**
     * Return if the consumer configuration of this stream is deferred.
     */
+13 −13
Original line number Diff line number Diff line
@@ -36,12 +36,12 @@ PreviewFrameSpacer::~PreviewFrameSpacer() {
    Thread::requestExitAndWait();
}

status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
        ANativeWindowBuffer* anwBuffer, int releaseFence) {
status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
        int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
    Mutex::Autolock l(mLock);
    mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
    ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
            mPendingBuffers.size(), timestamp);
    mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
    ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
            __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);

    mBufferCond.signal();
    return OK;
@@ -56,17 +56,17 @@ bool PreviewFrameSpacer::threadLoop() {

    nsecs_t currentTime = systemTime();
    auto buffer = mPendingBuffers.front();
    nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
    // If the capture interval exceeds threshold, directly queue
    nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
    // If the readout interval exceeds threshold, directly queue
    // cached buffer.
    if (captureInterval >= kFrameIntervalThreshold) {
    if (readoutInterval >= kFrameIntervalThreshold) {
        mPendingBuffers.pop();
        queueBufferToClientLocked(buffer, currentTime);
        return true;
    }

    // Cache the frame to match capture time interval, for up to 33ms
    nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
    // Cache the frame to match readout time interval, for up to 33ms
    nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval;
    nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
    if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
        mBufferCond.waitRelative(mLock, frameWaitTime);
@@ -75,8 +75,8 @@ bool PreviewFrameSpacer::threadLoop() {
        }
        currentTime = systemTime();
    }
    ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
            ", timestamp %" PRId64, __FUNCTION__, captureInterval,
    ALOGV("%s: readoutInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
            ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
            currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
    mPendingBuffers.pop();
    queueBufferToClientLocked(buffer, currentTime);
@@ -114,7 +114,7 @@ void PreviewFrameSpacer::queueBufferToClientLocked(
    }

    mLastCameraPresentTime = currentTime;
    mLastCameraCaptureTime = bufferHolder.timestamp;
    mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
}

}; // namespace camera3
+9 −7
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@ class Camera3OutputStream;
 *
 * The PreviewFrameSpacer improves the viewfinder user experience by:
 * - Cache the frame buffers if the intervals between queueBuffer is shorter
 *   than the camera capture intervals.
 * - Queue frame buffers in the same cadence as the camera capture time.
 *   than the camera readout intervals.
 * - Queue frame buffers in the same cadence as the camera readout time.
 * - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
 *   available, queue the oldest cached buffer to the buffer queue.
 */
@@ -53,8 +53,8 @@ class PreviewFrameSpacer : public Thread {
    virtual ~PreviewFrameSpacer();

    // Queue preview buffer locally
    status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
            ANativeWindowBuffer* anwBuffer, int releaseFence);
    status_t queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
            int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence);

    bool threadLoop() override;
    void requestExit() override;
@@ -63,12 +63,14 @@ class PreviewFrameSpacer : public Thread {
    // structure holding cached preview buffer info
    struct BufferHolder {
        nsecs_t timestamp;
        nsecs_t readoutTimestamp;
        int32_t transform;
        sp<ANativeWindowBuffer> anwBuffer;
        int releaseFence;

        BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
                timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
        BufferHolder(nsecs_t t, nsecs_t readoutT, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
                timestamp(t), readoutTimestamp(readoutT), transform(tr), anwBuffer(anwb),
                releaseFence(rf) {}
    };

    void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
@@ -80,7 +82,7 @@ class PreviewFrameSpacer : public Thread {
    Condition mBufferCond;

    std::queue<BufferHolder> mPendingBuffers;
    nsecs_t mLastCameraCaptureTime = 0;
    nsecs_t mLastCameraReadoutTime = 0;
    nsecs_t mLastCameraPresentTime = 0;
    static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
    static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms