Loading services/camera/libcameraservice/device3/Camera3Device.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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; } } Loading services/camera/libcameraservice/device3/Camera3FakeStream.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -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 services/camera/libcameraservice/device3/Camera3FakeStream.h +2 −0 Original line number Diff line number Diff line Loading @@ -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: /** Loading services/camera/libcameraservice/device3/Camera3OutputStream.cpp +148 −2 Original line number Diff line number Diff line Loading @@ -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>&) { Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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(), Loading Loading @@ -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 services/camera/libcameraservice/device3/Camera3OutputStream.h +30 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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. */ Loading Loading @@ -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); Loading Loading @@ -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 Loading
services/camera/libcameraservice/device3/Camera3Device.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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; } } Loading
services/camera/libcameraservice/device3/Camera3FakeStream.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -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
services/camera/libcameraservice/device3/Camera3FakeStream.h +2 −0 Original line number Diff line number Diff line Loading @@ -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: /** Loading
services/camera/libcameraservice/device3/Camera3OutputStream.cpp +148 −2 Original line number Diff line number Diff line Loading @@ -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>&) { Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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(), Loading Loading @@ -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
services/camera/libcameraservice/device3/Camera3OutputStream.h +30 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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. */ Loading Loading @@ -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); Loading Loading @@ -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