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

Commit e46a3f41 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Camera: batching dequeueBuffer call for batched requests"

parents 22eaca8a 14ef48d8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -913,6 +913,7 @@ status_t Camera3Device::convertMetadataListToRequestListLocked(
        for (auto& outputStream : (*firstRequest)->mOutputStreams) {
            if (outputStream->isVideoStream()) {
                (*firstRequest)->mBatchSize = requestList->size();
                outputStream->setBatchSize(requestList->size());
                break;
            }
        }
+5 −0
Original line number Diff line number Diff line
@@ -134,6 +134,11 @@ status_t Camera3FakeStream::updateStream(const std::vector<sp<Surface>> &/*outpu
    return INVALID_OPERATION;
}

status_t Camera3FakeStream::setBatchSize(size_t /*batchSize*/) {
    ALOGE("%s: this method is not supported!", __FUNCTION__);
    return INVALID_OPERATION;
}

}; // namespace camera3

}; // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -98,6 +98,8 @@ class Camera3FakeStream :
            const std::vector<size_t> &removedSurfaceIds,
            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);

    virtual status_t setBatchSize(size_t batchSize) override;

  protected:

    /**
+148 −2
Original line number Diff line number Diff line
@@ -189,6 +189,65 @@ status_t Camera3OutputStream::getBufferLocked(camera_stream_buffer *buffer,
    return OK;
}

status_t Camera3OutputStream::getBuffersLocked(std::vector<OutstandingBuffer>* outBuffers) {
    status_t res;

    if ((res = getBufferPreconditionCheckLocked()) != OK) {
        return res;
    }

    if (mUseBufferManager) {
        ALOGE("%s: stream %d is managed by buffer manager and does not support batch operation",
                __FUNCTION__, mId);
        return INVALID_OPERATION;
    }

    sp<Surface> consumer = mConsumer;
    /**
     * Release the lock briefly to avoid deadlock for below scenario:
     * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
     * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
     * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
     * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
     * StreamingProcessor lock.
     * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
     * and try to lock bufferQueue lock.
     * Then there is circular locking dependency.
     */
    mLock.unlock();

    size_t numBuffersRequested = outBuffers->size();
    std::vector<Surface::BatchBuffer> buffers(numBuffersRequested);

    nsecs_t dequeueStart = systemTime(SYSTEM_TIME_MONOTONIC);
    res = consumer->dequeueBuffers(&buffers);
    nsecs_t dequeueEnd = systemTime(SYSTEM_TIME_MONOTONIC);
    mDequeueBufferLatency.add(dequeueStart, dequeueEnd);

    mLock.lock();

    if (res != OK) {
        if (shouldLogError(res, mState)) {
            ALOGE("%s: Stream %d: Can't dequeue %zu output buffers: %s (%d)",
                    __FUNCTION__, mId, numBuffersRequested, strerror(-res), res);
        }
        checkRetAndSetAbandonedLocked(res);
        return res;
    }
    checkRemovedBuffersLocked();

    /**
     * FenceFD now owned by HAL except in case of error,
     * in which case we reassign it to acquire_fence
     */
    for (size_t i = 0; i < numBuffersRequested; i++) {
        handoutBufferLocked(*(outBuffers->at(i).outBuffer),
                &(buffers[i].buffer->handle), /*acquireFence*/buffers[i].fenceFd,
                /*releaseFence*/-1, CAMERA_BUFFER_STATUS_OK, /*output*/true);
    }
    return OK;
}

status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
            ANativeWindowBuffer* buffer, int anwReleaseFence,
            const std::vector<size_t>&) {
@@ -200,6 +259,10 @@ status_t Camera3OutputStream::returnBufferLocked(
        nsecs_t timestamp, const std::vector<size_t>& surface_ids) {
    ATRACE_HFR_CALL();

    if (mHandoutTotalBufferCount == 1) {
        returnPrefetchedBuffersLocked();
    }

    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true, surface_ids);

    if (res != OK) {
@@ -580,11 +643,46 @@ status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, i
         * and try to lock bufferQueue lock.
         * Then there is circular locking dependency.
         */
        sp<ANativeWindow> currentConsumer = mConsumer;
        sp<Surface> consumer = mConsumer;
        size_t remainingBuffers = camera_stream::max_buffers - mHandoutTotalBufferCount;
        mLock.unlock();
        std::unique_lock<std::mutex> batchLock(mBatchLock);

        nsecs_t dequeueStart = systemTime(SYSTEM_TIME_MONOTONIC);
        res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd);

        if (mBatchSize == 1) {
            sp<ANativeWindow> anw = consumer;
            res = anw->dequeueBuffer(anw.get(), anb, fenceFd);
        } else {
            res = OK;
            if (mBatchedBuffers.size() == 0) {
                size_t batchSize = mBatchSize;
                if (remainingBuffers == 0) {
                    ALOGE("%s: cannot get buffer while all buffers are handed out", __FUNCTION__);
                    return INVALID_OPERATION;
                }
                if (batchSize > remainingBuffers) {
                    batchSize = remainingBuffers;
                }
                // Refill batched buffers
                mBatchedBuffers.resize(batchSize);
                res = consumer->dequeueBuffers(&mBatchedBuffers);
                if (res != OK) {
                    ALOGE("%s: batch dequeueBuffers call failed! %s (%d)",
                            __FUNCTION__, strerror(-res), res);
                    mBatchedBuffers.clear();
                }
            }

            if (res == OK) {
                // Dispatch batch buffers
                *anb = mBatchedBuffers.back().buffer;
                *fenceFd = mBatchedBuffers.back().fenceFd;
                mBatchedBuffers.pop_back();
            }
        }
        batchLock.unlock();

        nsecs_t dequeueEnd = systemTime(SYSTEM_TIME_MONOTONIC);
        mDequeueBufferLatency.add(dequeueStart, dequeueEnd);

@@ -678,6 +776,8 @@ status_t Camera3OutputStream::disconnectLocked() {
        return OK;
    }

    returnPrefetchedBuffersLocked();

    ALOGV("%s: disconnecting stream %d from native window", __FUNCTION__, getId());

    res = native_window_api_disconnect(mConsumer.get(),
@@ -1013,6 +1113,52 @@ void Camera3OutputStream::dumpImageToDisk(nsecs_t timestamp,
    graphicBuffer->unlock();
}

status_t Camera3OutputStream::setBatchSize(size_t batchSize) {
    Mutex::Autolock l(mLock);
    std::lock_guard<std::mutex> lock(mBatchLock);
    if (batchSize == 0) {
        ALOGE("%s: invalid batch size 0", __FUNCTION__);
        return BAD_VALUE;
    }

    if (mUseBufferManager) {
        ALOGE("%s: batch operation is not supported with buffer manager", __FUNCTION__);
        return INVALID_OPERATION;
    }

    if (!isVideoStream()) {
        ALOGE("%s: batch operation is not supported with non-video stream", __FUNCTION__);
        return INVALID_OPERATION;
    }

    if (batchSize != mBatchSize) {
        if (mBatchedBuffers.size() != 0) {
            ALOGE("%s: change batch size from %zu to %zu dynamically is not supported",
                    __FUNCTION__, mBatchSize, batchSize);
            return INVALID_OPERATION;
        }

        if (camera_stream::max_buffers < batchSize) {
            ALOGW("%s: batch size is capped by max_buffers %d", __FUNCTION__,
                    camera_stream::max_buffers);
            batchSize = camera_stream::max_buffers;
        }
        mBatchSize = batchSize;
    }
    return OK;
}

void Camera3OutputStream::returnPrefetchedBuffersLocked() {
    std::lock_guard<std::mutex> batchLock(mBatchLock);
    if (mBatchedBuffers.size() != 0) {
        ALOGW("%s: %zu extra prefetched buffers detected. Returning",
                __FUNCTION__, mBatchedBuffers.size());

        mConsumer->cancelBuffers(mBatchedBuffers);
        mBatchedBuffers.clear();
    }
}

}; // namespace camera3

}; // namespace android
+30 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H
#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H

#include <mutex>
#include <utils/RefBase.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
@@ -205,6 +206,19 @@ class Camera3OutputStream :
            const std::vector<size_t> &removedSurfaceIds,
            KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);

    /**
     * Set the batch size for buffer operations. The output stream will request
     * buffers from buffer queue on a batch basis. Currently only video streams
     * are allowed to set the batch size. Also if the stream is managed by
     * buffer manager (Surface group in Java API) then batching is also not
     * supported. Changing batch size on the fly while there is already batched
     * buffers in the stream is also not supported.
     * If the batch size is larger than the max dequeue count set
     * by the camera HAL, the batch size will be set to the max dequeue count
     * instead.
     */
    virtual status_t setBatchSize(size_t batchSize = 1) override;

    /**
     * Apply ZSL related consumer usage quirk.
     */
@@ -292,12 +306,26 @@ class Camera3OutputStream :
    // Whether to drop valid buffers.
    bool mDropBuffers;


    // Protecting batch states below, must be acquired after mLock
    std::mutex mBatchLock;

    // The batch size for buffer operation
    size_t mBatchSize = 1;

    // Prefetched buffers (ready to be handed to client)
    std::vector<Surface::BatchBuffer> mBatchedBuffers;

    // ---- End of mBatchLock protected scope ----

    /**
     * Internal Camera3Stream interface
     */
    virtual status_t getBufferLocked(camera_stream_buffer *buffer,
            const std::vector<size_t>& surface_ids);

    virtual status_t getBuffersLocked(/*out*/std::vector<OutstandingBuffer>* buffers) override;

    virtual status_t returnBufferLocked(
            const camera_stream_buffer &buffer,
            nsecs_t timestamp, const std::vector<size_t>& surface_ids);
@@ -330,6 +358,8 @@ class Camera3OutputStream :
    // Dump images to disk before returning to consumer
    void dumpImageToDisk(nsecs_t timestamp, ANativeWindowBuffer* anwBuffer, int fence);

    void returnPrefetchedBuffersLocked();

    static const int32_t kDequeueLatencyBinSize = 5; // in ms
    CameraLatencyHistogram mDequeueBufferLatency;

Loading