From d5cd5ffe3ada6b71818d9957bd7ca68b10e54268 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Mon, 1 Oct 2018 14:43:04 -0700 Subject: [PATCH 1/3] Camera: implement buffer managment API Test: compile Bug: 109829698 Change-Id: I3d95792282da52db9db6fd6a086bbd7b3ff9dca9 --- .../device3/Camera3Device.cpp | 329 ++++++++++++++++-- .../libcameraservice/device3/Camera3Device.h | 80 +++-- .../device3/Camera3IOStreamBase.cpp | 2 +- .../device3/Camera3IOStreamBase.h | 2 +- .../device3/Camera3SharedOutputStream.cpp | 4 + .../device3/Camera3Stream.cpp | 6 + .../libcameraservice/device3/Camera3Stream.h | 7 +- .../device3/Camera3StreamInterface.h | 5 + 8 files changed, 360 insertions(+), 75 deletions(-) diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 2131cf8029..1d40d13c83 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -82,8 +82,6 @@ Camera3Device::Camera3Device(const String8 &id): mLastTemplateId(-1) { ATRACE_CALL(); - camera3_callback_ops::notify = &sNotify; - camera3_callback_ops::process_capture_result = &sProcessCaptureResult; ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string()); } @@ -218,8 +216,17 @@ status_t Camera3Device::initializeCommonLocked() { if (sessionKeysEntry.count > 0) { sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count); } + + camera_metadata_entry bufMgrMode = + mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION); + if (bufMgrMode.count > 0) { + mUseHalBufManager = (bufMgrMode.data.u8[0] == + ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5); + } + /** Start up request queue thread */ - mRequestThread = new RequestThread(this, mStatusTracker, mInterface, sessionParamKeys); + mRequestThread = new RequestThread( + this, mStatusTracker, mInterface, sessionParamKeys, mUseHalBufManager); res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string()); if (res != OK) { SET_ERR_L("Unable to start request queue thread: %s (%d)", @@ -271,7 +278,6 @@ status_t Camera3Device::initializeCommonLocked() { return res; } } - return OK; } @@ -919,6 +925,221 @@ status_t Camera3Device::submitRequestsHelper( return res; } +hardware::Return Camera3Device::requestStreamBuffers( + const hardware::hidl_vec& bufReqs, + requestStreamBuffers_cb _hidl_cb) { + using hardware::camera::device::V3_5::BufferRequestStatus; + using hardware::camera::device::V3_5::StreamBufferRet; + using hardware::camera::device::V3_5::StreamBufferRequestError; + + std::lock_guard lock(mRequestBufferInterfaceLock); + + hardware::hidl_vec bufRets; + if (!mUseHalBufManager) { + ALOGE("%s: Camera %s does not support HAL buffer management", + __FUNCTION__, mId.string()); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return hardware::Void(); + } + + SortedVector streamIds; + ssize_t sz = streamIds.setCapacity(bufReqs.size()); + if (sz < 0 || static_cast(sz) != bufReqs.size()) { + ALOGE("%s: failed to allocate memory for %zu buffer requests", + __FUNCTION__, bufReqs.size()); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return hardware::Void(); + } + + // Check for repeated streamId + for (const auto& bufReq : bufReqs) { + if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) { + ALOGE("%s: Stream %d appear multiple times in buffer requests", + __FUNCTION__, bufReq.streamId); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return hardware::Void(); + } + streamIds.add(bufReq.streamId); + } + + // TODO: check we are not configuring streams. If so return FAILED_CONFIGURING + // Probably need to hook CameraDeviceClient::beginConfigure and figure something + // out for API1 client... maybe grab mLock and check mNeedConfig but then we will + // need to wait until mLock is released... + // _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets); + // return hardware::Void(); + + // TODO: here we start accessing mOutputStreams, might need mLock, but that + // might block incoming API calls. Not sure how bad is it. + if (bufReqs.size() > mOutputStreams.size()) { + ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)", + __FUNCTION__, bufReqs.size(), mOutputStreams.size()); + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets); + return hardware::Void(); + } + + bufRets.resize(bufReqs.size()); + + bool allReqsSucceeds = true; + bool oneReqSucceeds = false; + for (size_t i = 0; i < bufReqs.size(); i++) { + const auto& bufReq = bufReqs[i]; + auto& bufRet = bufRets[i]; + int32_t streamId = bufReq.streamId; + ssize_t idx = mOutputStreams.indexOfKey(streamId); + if (idx == NAME_NOT_FOUND) { + ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId); + hardware::hidl_vec emptyBufRets; + _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets); + return hardware::Void(); + } + sp outputStream = mOutputStreams.valueAt(idx); + + bufRet.streamId = streamId; + uint32_t numBuffersRequested = bufReq.numBuffersRequested; + size_t totalHandout = outputStream->getOutstandingBuffersCount() + numBuffersRequested; + if (totalHandout > outputStream->asHalStream()->max_buffers) { + // Not able to allocate enough buffer. Exit early for this stream + bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); + allReqsSucceeds = false; + continue; + } + + hardware::hidl_vec tmpRetBuffers(numBuffersRequested); + bool currentReqSucceeds = true; + std::vector streamBuffers(numBuffersRequested); + size_t numAllocatedBuffers = 0; + size_t numPushedInflightBuffers = 0; + for (size_t b = 0; b < numBuffersRequested; b++) { + camera3_stream_buffer_t& sb = streamBuffers[b]; + // Since this method can run concurrently with request thread + // We need to update the wait duration everytime we call getbuffer + nsecs_t waitDuration = kBaseGetBufferWait + getExpectedInFlightDuration(); + status_t res = outputStream->getBuffer(&sb, waitDuration); + if (res != OK) { + ALOGE("%s: Can't get output buffer for stream %d: %s (%d)", + __FUNCTION__, streamId, strerror(-res), res); + if (res == NO_INIT || res == DEAD_OBJECT) { + bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED); + } else if (res == TIMED_OUT || res == NO_MEMORY) { + bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE); + } else { + bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR); + } + currentReqSucceeds = false; + break; + } + numAllocatedBuffers++; + + buffer_handle_t *buffer = sb.buffer; + auto pair = mInterface->getBufferId(*buffer, streamId); + bool isNewBuffer = pair.first; + uint64_t bufferId = pair.second; + StreamBuffer& hBuf = tmpRetBuffers[b]; + + hBuf.streamId = streamId; + hBuf.bufferId = bufferId; + hBuf.buffer = (isNewBuffer) ? *buffer : nullptr; + hBuf.status = BufferStatus::OK; + hBuf.releaseFence = nullptr; + + native_handle_t *acquireFence = nullptr; + if (sb.acquire_fence != -1) { + acquireFence = native_handle_create(1,0); + acquireFence->data[0] = sb.acquire_fence; + } + hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true); + hBuf.releaseFence = nullptr; + + res = mInterface->pushInflightRequestBuffer(bufferId, buffer); + if (res != OK) { + ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)", + __FUNCTION__, streamId, strerror(-res), res); + bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR); + currentReqSucceeds = false; + break; + } + numPushedInflightBuffers++; + } + if (currentReqSucceeds) { + bufRet.val.buffers(std::move(tmpRetBuffers)); + oneReqSucceeds = true; + } else { + allReqsSucceeds = false; + for (size_t b = 0; b < numPushedInflightBuffers; b++) { + StreamBuffer& hBuf = tmpRetBuffers[b]; + buffer_handle_t* buffer; + status_t res = mInterface->popInflightRequestBuffer(hBuf.bufferId, &buffer); + if (res != OK) { + SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)", + __FUNCTION__, streamId, strerror(-res), res); + } + } + returnOutputBuffers(streamBuffers.data(), numAllocatedBuffers, 0); + } + } + // End of mOutputStreams access + + _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK : + oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL : + BufferRequestStatus::FAILED_UNKNOWN, + bufRets); + return hardware::Void(); +} + +hardware::Return Camera3Device::returnStreamBuffers( + const hardware::hidl_vec& buffers) { + if (!mUseHalBufManager) { + ALOGE("%s: Camera %s does not support HAL buffer managerment", + __FUNCTION__, mId.string()); + return hardware::Void(); + } + + for (const auto& buf : buffers) { + if (buf.bufferId == HalInterface::BUFFER_ID_NO_BUFFER) { + ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__); + continue; + } + + buffer_handle_t* buffer; + status_t res = mInterface->popInflightRequestBuffer(buf.bufferId, &buffer); + + if (res != OK) { + ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d", + __FUNCTION__, buf.bufferId, buf.streamId); + continue; + } + + camera3_stream_buffer_t streamBuffer; + streamBuffer.buffer = buffer; + streamBuffer.status = CAMERA3_BUFFER_STATUS_ERROR; + streamBuffer.acquire_fence = -1; + streamBuffer.release_fence = -1; + + if (buf.releaseFence == nullptr) { + streamBuffer.release_fence = -1; + } else if (buf.releaseFence->numFds == 1) { + streamBuffer.release_fence = dup(buf.releaseFence->data[0]); + } else { + ALOGE("%s: Invalid release fence, fd count is %d, not 1", + __FUNCTION__, buf.releaseFence->numFds); + continue; + } + + // Need to lock mLock here if we were to allow HAL to return buffer during + // stream configuration. This is not currently possible because we only + // do stream configuration when there is no inflight buffers in HAL. + ssize_t idx = mOutputStreams.indexOfKey(buf.streamId); + if (idx == NAME_NOT_FOUND) { + ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId); + continue; + } + streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream(); + returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0); + } + return hardware::Void(); +} + hardware::Return Camera3Device::processCaptureResult_3_4( const hardware::hidl_vec< hardware::camera::device::V3_4::CaptureResult>& results) { @@ -1076,12 +1297,23 @@ void Camera3Device::processOneCaptureResultLocked( bDst.stream = mOutputStreams.valueAt(idx)->asHalStream(); buffer_handle_t *buffer; - res = mInterface->popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer); + if (mUseHalBufManager) { + if (bSrc.bufferId == HalInterface::BUFFER_ID_NO_BUFFER) { + ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d", + __FUNCTION__, result.frameNumber, i, bSrc.streamId); + return; + } + res = mInterface->popInflightRequestBuffer(bSrc.bufferId, &buffer); + } else { + res = mInterface->popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer); + } + if (res != OK) { ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d", __FUNCTION__, result.frameNumber, i, bSrc.streamId); return; } + bDst.buffer = buffer; bDst.status = mapHidlBufferStatus(bSrc.status); bDst.acquire_fence = -1; @@ -3475,6 +3707,10 @@ Camera3Device::HalInterface::HalInterface( mRequestMetadataQueue(queue) { // Check with hardware service manager if we can downcast these interfaces // Somewhat expensive, so cache the results at startup + auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession); + if (castResult_3_5.isOk()) { + mHidlSession_3_5 = castResult_3_5; + } auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession); if (castResult_3_4.isOk()) { mHidlSession_3_4 = castResult_3_4; @@ -4081,6 +4317,33 @@ status_t Camera3Device::HalInterface::popInflightBuffer( return OK; } +status_t Camera3Device::HalInterface::pushInflightRequestBuffer( + uint64_t bufferId, buffer_handle_t* buf) { + std::lock_guard lock(mRequestedBuffersLock); + auto pair = mRequestedBuffers.insert({bufferId, buf}); + if (!pair.second) { + ALOGE("%s: bufId %" PRIu64 " is already inflight!", + __FUNCTION__, bufferId); + return BAD_VALUE; + } + return OK; +} + +// Find and pop a buffer_handle_t based on bufferId +status_t Camera3Device::HalInterface::popInflightRequestBuffer( + uint64_t bufferId, /*out*/ buffer_handle_t **buffer) { + std::lock_guard lock(mRequestedBuffersLock); + auto it = mRequestedBuffers.find(bufferId); + if (it == mRequestedBuffers.end()) { + ALOGE("%s: bufId %" PRIu64 " is not inflight!", + __FUNCTION__, bufferId); + return BAD_VALUE; + } + *buffer = it->second; + mRequestedBuffers.erase(it); + return OK; +} + std::pair Camera3Device::HalInterface::getBufferId( const buffer_handle_t& buf, int streamId) { std::lock_guard lock(mBufferIdMapLock); @@ -4129,7 +4392,8 @@ void Camera3Device::HalInterface::onBufferFreed( Camera3Device::RequestThread::RequestThread(wp parent, sp statusTracker, - sp interface, const Vector& sessionParamKeys) : + sp interface, const Vector& sessionParamKeys, + bool useHalBufManager) : Thread(/*canCallJava*/false), mParent(parent), mStatusTracker(statusTracker), @@ -4149,7 +4413,8 @@ Camera3Device::RequestThread::RequestThread(wp parent, mConstrainedMode(false), mRequestLatency(kRequestLatencyBinSize), mSessionParamKeys(sessionParamKeys), - mLatestSessionParams(sessionParamKeys.size()) { + mLatestSessionParams(sessionParamKeys.size()), + mUseHalBufManager(useHalBufManager) { mStatusId = statusTracker->addComponent(); } @@ -4928,16 +5193,27 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { } } - res = outputStream->getBuffer(&outputBuffers->editItemAt(j), - waitDuration, - captureRequest->mOutputSurfaces[outputStream->getId()]); - if (res != OK) { - // Can't get output buffer from gralloc queue - this could be due to - // abandoned queue or other consumer misbehavior, so not a fatal - // error - ALOGE("RequestThread: Can't get output buffer, skipping request:" - " %s (%d)", strerror(-res), res); - return TIMED_OUT; + if (mUseHalBufManager) { + // HAL will request buffer through requestStreamBuffer API + camera3_stream_buffer_t& buffer = outputBuffers->editItemAt(j); + buffer.stream = outputStream->asHalStream(); + buffer.buffer = nullptr; + buffer.status = CAMERA3_BUFFER_STATUS_OK; + buffer.acquire_fence = -1; + buffer.release_fence = -1; + } else { + res = outputStream->getBuffer(&outputBuffers->editItemAt(j), + waitDuration, + captureRequest->mOutputSurfaces[outputStream->getId()]); + if (res != OK) { + // Can't get output buffer from gralloc queue - this could be due to + // abandoned queue or other consumer misbehavior, so not a fatal + // error + ALOGE("RequestThread: Can't get output buffer, skipping request:" + " %s (%d)", strerror(-res), res); + + return TIMED_OUT; + } } String8 physicalCameraId = outputStream->getPhysicalCameraId(); @@ -5794,23 +6070,4 @@ bool Camera3Device::PreparerThread::threadLoop() { return true; } -/** - * Static callback forwarding methods from HAL to instance - */ - -void Camera3Device::sProcessCaptureResult(const camera3_callback_ops *cb, - const camera3_capture_result *result) { - Camera3Device *d = - const_cast(static_cast(cb)); - - d->processCaptureResult(result); -} - -void Camera3Device::sNotify(const camera3_callback_ops *cb, - const camera3_notify_msg *msg) { - Camera3Device *d = - const_cast(static_cast(cb)); - d->notify(msg); -} - }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 5e749b6d48..7656ef33cd 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -33,10 +33,11 @@ #include #include #include +#include #include #include +#include #include -#include #include @@ -50,20 +51,6 @@ using android::camera3::OutputStreamInfo; -/** - * Function pointer types with C calling convention to - * use for HAL callback functions. - */ -extern "C" { - typedef void (callbacks_process_capture_result_t)( - const struct camera3_callback_ops *, - const camera3_capture_result_t *); - - typedef void (callbacks_notify_t)( - const struct camera3_callback_ops *, - const camera3_notify_msg_t *); -} - namespace android { namespace camera3 { @@ -80,8 +67,7 @@ class Camera3StreamInterface; */ class Camera3Device : public CameraDeviceBase, - virtual public hardware::camera::device::V3_4::ICameraDeviceCallback, - private camera3_callback_ops { + virtual public hardware::camera::device::V3_5::ICameraDeviceCallback { public: explicit Camera3Device(const String8& id); @@ -299,14 +285,25 @@ class Camera3Device : status_t dump(int fd); status_t close(); + // method to extract buffer's unique ID + // return pair of (newlySeenBuffer?, bufferId) + std::pair getBufferId(const buffer_handle_t& buf, int streamId); + // Find a buffer_handle_t based on frame number and stream ID status_t popInflightBuffer(int32_t frameNumber, int32_t streamId, /*out*/ buffer_handle_t **buffer); + // Register a bufId/buffer_handle_t to inflight request buffer + status_t pushInflightRequestBuffer(uint64_t bufferId, buffer_handle_t* buf); + + // Find a buffer_handle_t based on bufferId + status_t popInflightRequestBuffer(uint64_t bufferId, /*out*/ buffer_handle_t **buffer); + // Get a vector of (frameNumber, streamId) pair of currently inflight // buffers void getInflightBufferKeys(std::vector>* out); + static const uint64_t BUFFER_ID_NO_BUFFER = 0; private: // Always valid sp mHidlSession; @@ -314,6 +311,8 @@ class Camera3Device : sp mHidlSession_3_3; // Valid if ICameraDeviceSession is @3.4 or newer sp mHidlSession_3_4; + // Valid if ICameraDeviceSession is @3.5 or newer + sp mHidlSession_3_5; std::shared_ptr mRequestMetadataQueue; @@ -365,19 +364,14 @@ class Camera3Device : // stream ID -> per stream buffer ID map std::unordered_map mBufferIdMaps; uint64_t mNextBufferId = 1; // 0 means no buffer - static const uint64_t BUFFER_ID_NO_BUFFER = 0; - - // method to extract buffer's unique ID - // TODO: we should switch to use gralloc mapper's getBackingStore API - // once we ran in binderized gralloc mode, but before that is ready, - // we need to rely on the conventional buffer queue behavior where - // buffer_handle_t's FD won't change. - // return pair of (newlySeenBuffer?, bufferId) - std::pair getBufferId(const buffer_handle_t& buf, int streamId); virtual void onBufferFreed(int streamId, const native_handle_t* handle) override; std::vector> mFreedBuffers; + + // Buffers given to HAL through requestStreamBuffer API + std::mutex mRequestedBuffersLock; + std::unordered_map mRequestedBuffers; }; sp mInterface; @@ -483,8 +477,9 @@ class Camera3Device : /** - * Implementation of android::hardware::camera::device::V3_4::ICameraDeviceCallback + * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback */ + hardware::Return processCaptureResult_3_4( const hardware::hidl_vec< hardware::camera::device::V3_4::CaptureResult>& results) override; @@ -495,6 +490,15 @@ class Camera3Device : const hardware::hidl_vec< hardware::camera::device::V3_2::NotifyMsg>& msgs) override; + hardware::Return requestStreamBuffers( + const hardware::hidl_vec< + hardware::camera::device::V3_5::BufferRequest>& bufReqs, + requestStreamBuffers_cb _hidl_cb) override; + + hardware::Return returnStreamBuffers( + const hardware::hidl_vec< + hardware::camera::device::V3_2::StreamBuffer>& buffers) override; + // Handle one capture result. Assume that mProcessCaptureResultLock is held. void processOneCaptureResultLocked( const hardware::camera::device::V3_2::CaptureResult& result, @@ -702,7 +706,9 @@ class Camera3Device : RequestThread(wp parent, sp statusTracker, - sp interface, const Vector& sessionParamKeys); + sp interface, + const Vector& sessionParamKeys, + bool useHalBufManager); ~RequestThread(); void setNotificationListener(wp listener); @@ -937,6 +943,8 @@ class Camera3Device : Vector mSessionParamKeys; CameraMetadata mLatestSessionParams; + + const bool mUseHalBufManager; }; sp mRequestThread; @@ -1020,7 +1028,7 @@ class Camera3Device : InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput, bool hasAppCallback, nsecs_t maxDuration, - const std::set& physicalCameraIdSet, bool isStillCapture, + const std::set& physicalCameraIdSet, bool isStillCapture, bool isZslCapture) : shutterTimestamp(0), sensorTimestamp(0), @@ -1217,16 +1225,16 @@ class Camera3Device : // Cached last requested template id int mLastTemplateId; - /** - * Static callback forwarding methods from HAL to instance - */ - static callbacks_process_capture_result_t sProcessCaptureResult; - - static callbacks_notify_t sNotify; - // Synchronizes access to status tracker between inflight updates and disconnect. // b/79972865 Mutex mTrackerLock; + + // Whether HAL request buffers through requestStreamBuffer API + bool mUseHalBufManager = false; + + // Lock to ensure requestStreamBuffers() callbacks are serialized + std::mutex mRequestBufferInterfaceLock; + }; // class Camera3Device }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index 3c1e43d9b4..18b8c4d613 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -116,7 +116,7 @@ size_t Camera3IOStreamBase::getBufferCountLocked() { return mTotalBufferCount; } -size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() { +size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() const { return mHandoutOutputBufferCount; } diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index 0a31d444b9..48e9bbf846 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -82,7 +82,7 @@ class Camera3IOStreamBase : virtual size_t getBufferCountLocked(); - virtual size_t getHandoutOutputBufferCountLocked(); + virtual size_t getHandoutOutputBufferCountLocked() const; virtual size_t getHandoutInputBufferCountLocked(); diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp index fb3ce4c619..1c13950950 100644 --- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp @@ -138,6 +138,10 @@ status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffe return res; } + // TODO: need to refactor this to support requestStreamBuffers API + // Need to wait until processCaptureResult to decide the source buffer + // to attach to output... + // Attach the buffer to the splitter output queues. This could block if // the output queue doesn't have any empty slot. So unlock during the course // of attachBufferToOutputs. diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index ee989e12ed..0a30a97631 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -795,6 +795,12 @@ bool Camera3Stream::hasOutstandingBuffers() const { return hasOutstandingBuffersLocked(); } +size_t Camera3Stream::getOutstandingBuffersCount() const { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return getHandoutOutputBufferCountLocked(); +} + status_t Camera3Stream::setStatusTracker(sp statusTracker) { Mutex::Autolock l(mLock); sp oldTracker = mStatusTracker.promote(); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 1c67fb2e74..e29c3e00ae 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -360,6 +360,11 @@ class Camera3Stream : */ bool hasOutstandingBuffers() const; + /** + * Get number of buffers currently handed out to HAL + */ + size_t getOutstandingBuffersCount() const; + enum { TIMEOUT_NEVER = -1 }; @@ -495,7 +500,7 @@ class Camera3Stream : virtual size_t getBufferCountLocked() = 0; // Get handout output buffer count. - virtual size_t getHandoutOutputBufferCountLocked() = 0; + virtual size_t getHandoutOutputBufferCountLocked() const = 0; // Get handout input buffer count. virtual size_t getHandoutInputBufferCountLocked() = 0; diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 5758ac8203..866b7224f8 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -289,6 +289,11 @@ class Camera3StreamInterface : public virtual RefBase { */ virtual bool hasOutstandingBuffers() const = 0; + /** + * Get number of buffers currently handed out to HAL + */ + virtual size_t getOutstandingBuffersCount() const = 0; + enum { TIMEOUT_NEVER = -1 }; From 4ee35438095692be67245afb5100384b558bac71 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Wed, 10 Oct 2018 13:52:31 -0700 Subject: [PATCH 2/3] Camera: synchronize mOutputStreams access mOutputStreams access used to be protected by mLock, but that has changed due to: - Treble interface switched from passing stream pointer to stream index - The buffer management API runs in HAL callback thread Test: CTS Bug: 109829698 Change-Id: I3561b197f46f07d2a15bb4f52b096f36c73a0407 --- .../device3/Camera3Device.cpp | 185 ++++++++++-------- .../libcameraservice/device3/Camera3Device.h | 18 +- 2 files changed, 115 insertions(+), 88 deletions(-) diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 1d40d13c83..04d3639283 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -986,14 +986,13 @@ hardware::Return Camera3Device::requestStreamBuffers( const auto& bufReq = bufReqs[i]; auto& bufRet = bufRets[i]; int32_t streamId = bufReq.streamId; - ssize_t idx = mOutputStreams.indexOfKey(streamId); - if (idx == NAME_NOT_FOUND) { + sp outputStream = mOutputStreams.get(streamId); + if (outputStream == nullptr) { ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId); hardware::hidl_vec emptyBufRets; _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets); return hardware::Void(); } - sp outputStream = mOutputStreams.valueAt(idx); bufRet.streamId = streamId; uint32_t numBuffersRequested = bufReq.numBuffersRequested; @@ -1126,15 +1125,12 @@ hardware::Return Camera3Device::returnStreamBuffers( continue; } - // Need to lock mLock here if we were to allow HAL to return buffer during - // stream configuration. This is not currently possible because we only - // do stream configuration when there is no inflight buffers in HAL. - ssize_t idx = mOutputStreams.indexOfKey(buf.streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(buf.streamId); + if (stream == nullptr) { ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId); continue; } - streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream(); + streamBuffer.stream = stream->asHalStream(); returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0); } return hardware::Void(); @@ -1288,13 +1284,13 @@ void Camera3Device::processOneCaptureResultLocked( auto& bDst = outputBuffers[i]; const StreamBuffer &bSrc = result.outputBuffers[i]; - ssize_t idx = mOutputStreams.indexOfKey(bSrc.streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(bSrc.streamId); + if (stream == nullptr) { ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d", __FUNCTION__, result.frameNumber, i, bSrc.streamId); return; } - bDst.stream = mOutputStreams.valueAt(idx)->asHalStream(); + bDst.stream = stream->asHalStream(); buffer_handle_t *buffer; if (mUseHalBufManager) { @@ -1395,13 +1391,13 @@ void Camera3Device::notify( m.type = CAMERA3_MSG_ERROR; m.message.error.frame_number = msg.msg.error.frameNumber; if (msg.msg.error.errorStreamId >= 0) { - ssize_t idx = mOutputStreams.indexOfKey(msg.msg.error.errorStreamId); - if (idx == NAME_NOT_FOUND) { - ALOGE("%s: Frame %d: Invalid error stream id %d", - __FUNCTION__, m.message.error.frame_number, msg.msg.error.errorStreamId); + sp stream = mOutputStreams.get(msg.msg.error.errorStreamId); + if (stream == nullptr) { + ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__, + m.message.error.frame_number, msg.msg.error.errorStreamId); return; } - m.message.error.error_stream = mOutputStreams.valueAt(idx)->asHalStream(); + m.message.error.error_stream = stream->asHalStream(); } else { m.message.error.error_stream = nullptr; } @@ -1582,6 +1578,47 @@ status_t Camera3Device::createInputStream( return OK; } +status_t Camera3Device::StreamSet::add( + int streamId, sp stream) { + if (stream == nullptr) { + ALOGE("%s: cannot add null stream", __FUNCTION__); + return BAD_VALUE; + } + std::lock_guard lock(mLock); + return mData.add(streamId, stream); +} + +ssize_t Camera3Device::StreamSet::remove(int streamId) { + std::lock_guard lock(mLock); + return mData.removeItem(streamId); +} + +sp +Camera3Device::StreamSet::get(int streamId) { + std::lock_guard lock(mLock); + ssize_t idx = mData.indexOfKey(streamId); + if (idx == NAME_NOT_FOUND) { + return nullptr; + } + return mData.editValueAt(idx); +} + +sp +Camera3Device::StreamSet::operator[] (size_t index) { + std::lock_guard lock(mLock); + return mData.editValueAt(index); +} + +size_t Camera3Device::StreamSet::size() const { + std::lock_guard lock(mLock); + return mData.size(); +} + +void Camera3Device::StreamSet::clear() { + std::lock_guard lock(mLock); + return mData.clear(); +} + status_t Camera3Device::createStream(sp consumer, uint32_t width, uint32_t height, int format, android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id, @@ -1765,20 +1802,20 @@ status_t Camera3Device::getStreamInfo(int id, StreamInfo *streamInfo) { return INVALID_OPERATION; } - ssize_t idx = mOutputStreams.indexOfKey(id); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(id); + if (stream == nullptr) { CLOGE("Stream %d is unknown", id); - return idx; + return BAD_VALUE; } - streamInfo->width = mOutputStreams[idx]->getWidth(); - streamInfo->height = mOutputStreams[idx]->getHeight(); - streamInfo->format = mOutputStreams[idx]->getFormat(); - streamInfo->dataSpace = mOutputStreams[idx]->getDataSpace(); - streamInfo->formatOverridden = mOutputStreams[idx]->isFormatOverridden(); - streamInfo->originalFormat = mOutputStreams[idx]->getOriginalFormat(); - streamInfo->dataSpaceOverridden = mOutputStreams[idx]->isDataSpaceOverridden(); - streamInfo->originalDataSpace = mOutputStreams[idx]->getOriginalDataSpace(); + streamInfo->width = stream->getWidth(); + streamInfo->height = stream->getHeight(); + streamInfo->format = stream->getFormat(); + streamInfo->dataSpace = stream->getDataSpace(); + streamInfo->formatOverridden = stream->isFormatOverridden(); + streamInfo->originalFormat = stream->getOriginalFormat(); + streamInfo->dataSpaceOverridden = stream->isDataSpaceOverridden(); + streamInfo->originalDataSpace = stream->getOriginalDataSpace(); return OK; } @@ -1805,14 +1842,12 @@ status_t Camera3Device::setStreamTransform(int id, return INVALID_OPERATION; } - ssize_t idx = mOutputStreams.indexOfKey(id); - if (idx == NAME_NOT_FOUND) { - CLOGE("Stream %d does not exist", - id); + sp stream = mOutputStreams.get(id); + if (stream == nullptr) { + CLOGE("Stream %d does not exist", id); return BAD_VALUE; } - - return mOutputStreams.editValueAt(idx)->setTransform(transform); + return stream->setTransform(transform); } status_t Camera3Device::deleteStream(int id) { @@ -1837,21 +1872,21 @@ status_t Camera3Device::deleteStream(int id) { } sp deletedStream; - ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id); + sp stream = mOutputStreams.get(id); if (mInputStream != NULL && id == mInputStream->getId()) { deletedStream = mInputStream; mInputStream.clear(); } else { - if (outputStreamIdx == NAME_NOT_FOUND) { + if (stream == nullptr) { CLOGE("Stream %d does not exist", id); return BAD_VALUE; } } // Delete output stream or the output part of a bi-directional stream. - if (outputStreamIdx != NAME_NOT_FOUND) { - deletedStream = mOutputStreams.editValueAt(outputStreamIdx); - mOutputStreams.removeItem(id); + if (stream != nullptr) { + deletedStream = stream; + mOutputStreams.remove(id); } // Free up the stream endpoint so that it can be used by some other stream @@ -2270,15 +2305,12 @@ status_t Camera3Device::prepare(int maxCount, int streamId) { Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - sp stream; - ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId); - if (outputStreamIdx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { CLOGE("Stream %d does not exist", streamId); return BAD_VALUE; } - stream = mOutputStreams.editValueAt(outputStreamIdx); - if (stream->isUnpreparable() || stream->hasOutstandingBuffers() ) { CLOGE("Stream %d has already been a request target", streamId); return BAD_VALUE; @@ -2298,15 +2330,12 @@ status_t Camera3Device::tearDown(int streamId) { Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - sp stream; - ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId); - if (outputStreamIdx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { CLOGE("Stream %d does not exist", streamId); return BAD_VALUE; } - stream = mOutputStreams.editValueAt(outputStreamIdx); - if (stream->hasOutstandingBuffers() || mRequestThread->isStreamPending(stream)) { CLOGE("Stream %d is a target of a in-progress request", streamId); return BAD_VALUE; @@ -2322,14 +2351,11 @@ status_t Camera3Device::addBufferListenerForStream(int streamId, Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - sp stream; - ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId); - if (outputStreamIdx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { CLOGE("Stream %d does not exist", streamId); return BAD_VALUE; } - - stream = mOutputStreams.editValueAt(outputStreamIdx); stream->addBufferListener(listener); return OK; @@ -2388,12 +2414,11 @@ status_t Camera3Device::setConsumerSurfaces(int streamId, return BAD_VALUE; } - ssize_t idx = mOutputStreams.indexOfKey(streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { CLOGE("Stream %d is unknown", streamId); - return idx; + return BAD_VALUE; } - sp stream = mOutputStreams[idx]; status_t res = stream->setConsumers(consumers); if (res != OK) { CLOGE("Stream %d set consumer failed (error %d %s) ", streamId, res, strerror(-res)); @@ -2438,10 +2463,10 @@ status_t Camera3Device::updateStream(int streamId, const std::vector Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - ssize_t idx = mOutputStreams.indexOfKey(streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { CLOGE("Stream %d is unknown", streamId); - return idx; + return BAD_VALUE; } for (const auto &it : removedSurfaceIds) { @@ -2451,7 +2476,6 @@ status_t Camera3Device::updateStream(int streamId, const std::vector } } - sp stream = mOutputStreams[idx]; status_t res = stream->updateStream(newSurfaces, outputInfo, removedSurfaceIds, outputMap); if (res != OK) { CLOGE("Stream %d failed to update stream (error %d %s) ", @@ -2470,13 +2494,11 @@ status_t Camera3Device::dropStreamBuffers(bool dropping, int streamId) { Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - int idx = mOutputStreams.indexOfKey(streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { ALOGE("%s: Stream %d is not found.", __FUNCTION__, streamId); return BAD_VALUE; } - - sp stream = mOutputStreams.editValueAt(idx); return stream->dropBuffers(dropping); } @@ -2530,15 +2552,12 @@ sp Camera3Device::createCaptureRequest( } for (size_t i = 0; i < streams.count; i++) { - int idx = mOutputStreams.indexOfKey(streams.data.i32[i]); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streams.data.i32[i]); + if (stream == nullptr) { CLOGE("Request references unknown stream %d", - streams.data.u8[i]); + streams.data.i32[i]); return NULL; } - sp stream = - mOutputStreams.editValueAt(idx); - // It is illegal to include a deferred consumer output stream into a request auto iter = surfaceMap.find(streams.data.i32[i]); if (iter != surfaceMap.end()) { @@ -2599,7 +2618,7 @@ void Camera3Device::cancelStreamsConfigurationLocked() { } for (size_t i = 0; i < mOutputStreams.size(); i++) { - sp outputStream = mOutputStreams.editValueAt(i); + sp outputStream = mOutputStreams[i]; if (outputStream->isConfiguring()) { res = outputStream->cancelConfiguration(); if (res != OK) { @@ -2734,7 +2753,7 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, } camera3_stream_t *outputStream; - outputStream = mOutputStreams.editValueAt(i)->startConfiguration(); + outputStream = mOutputStreams[i]->startConfiguration(); if (outputStream == NULL) { CLOGE("Can't start output stream configuration"); cancelStreamsConfigurationLocked(); @@ -2792,8 +2811,7 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode, } for (size_t i = 0; i < mOutputStreams.size(); i++) { - sp outputStream = - mOutputStreams.editValueAt(i); + sp outputStream = mOutputStreams[i]; if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) { res = outputStream->finishConfiguration(); if (res != OK) { @@ -2900,15 +2918,12 @@ status_t Camera3Device::tryRemoveDummyStreamLocked() { // Ok, have a dummy stream and there's at least one other output stream, // so remove the dummy - sp deletedStream; - ssize_t outputStreamIdx = mOutputStreams.indexOfKey(mDummyStreamId); - if (outputStreamIdx == NAME_NOT_FOUND) { + sp deletedStream = mOutputStreams.get(mDummyStreamId); + if (deletedStream == nullptr) { SET_ERR_L("Dummy stream %d does not appear to exist", mDummyStreamId); return INVALID_OPERATION; } - - deletedStream = mOutputStreams.editValueAt(outputStreamIdx); - mOutputStreams.removeItemsAt(outputStreamIdx); + mOutputStreams.remove(mDummyStreamId); // Free up the stream endpoint so that it can be used by some other stream res = deletedStream->disconnect(); @@ -3175,12 +3190,12 @@ void Camera3Device::flushInflightRequests() { frameNumber, streamId, strerror(-res), res); } } else { - ssize_t idx = mOutputStreams.indexOfKey(streamId); - if (idx == NAME_NOT_FOUND) { + sp stream = mOutputStreams.get(streamId); + if (stream == nullptr) { ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId); continue; } - streamBuffer.stream = mOutputStreams.valueAt(idx)->asHalStream(); + streamBuffer.stream = stream->asHalStream(); returnOutputBuffers(&streamBuffer, /*size*/1, /*timestamp*/ 0); } } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 7656ef33cd..4ed6d9dd6b 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -406,9 +406,21 @@ class Camera3Device : // Tracking cause of fatal errors when in STATUS_ERROR String8 mErrorCause; - // Mapping of stream IDs to stream instances - typedef KeyedVector > - StreamSet; + // Synchronized mapping of stream IDs to stream instances + class StreamSet { + public: + status_t add(int streamId, sp); + ssize_t remove(int streamId); + sp get(int streamId); + // get by (underlying) vector index + sp operator[] (size_t index); + size_t size() const; + void clear(); + + private: + mutable std::mutex mLock; + KeyedVector> mData; + }; StreamSet mOutputStreams; sp mInputStream; From 7447f0fc15347d0fe4d5cda256fe680c50391a93 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Thu, 11 Oct 2018 15:28:12 -0700 Subject: [PATCH 3/3] Camera: implement signalPipelineDrain API SignalPipelineDrain will be sent after the request thread has stopped sending capture requests so HAL can expect no more capture requests are sent after they receive this call. Test: CTS Bug: 109829698 Change-Id: I6f75c28ff0998a8edc80f9af9ebe727c585ea6e9 --- .../device3/Camera3Device.cpp | 106 +++++++++++++++--- .../libcameraservice/device3/Camera3Device.h | 12 +- 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 04d3639283..f829b65eea 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -1619,6 +1619,15 @@ void Camera3Device::StreamSet::clear() { return mData.clear(); } +std::vector Camera3Device::StreamSet::getStreamIds() { + std::lock_guard lock(mLock); + std::vector streamIds(mData.size()); + for (size_t i = 0; i < mData.size(); i++) { + streamIds[i] = mData.keyAt(i); + } + return streamIds; +} + status_t Camera3Device::createStream(sp consumer, uint32_t width, uint32_t height, int format, android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id, @@ -2130,6 +2139,12 @@ status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) { break; } + // Notify HAL to start draining + if (!active && mUseHalBufManager) { + auto streamIds = mOutputStreams.getStreamIds(); + mRequestThread->signalPipelineDrain(streamIds); + } + res = mStatusChanged.waitRelative(mLock, timeout); if (res != OK) break; @@ -3902,26 +3917,49 @@ status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t * // Invoke configureStreams device::V3_3::HalStreamConfiguration finalConfiguration; + device::V3_4::HalStreamConfiguration finalConfiguration3_4; common::V1_0::Status status; - // See if we have v3.4 or v3.3 HAL - if (mHidlSession_3_4 != nullptr) { - // We do; use v3.4 for the call - ALOGV("%s: v3.4 device found", __FUNCTION__); - device::V3_4::HalStreamConfiguration finalConfiguration3_4; - auto err = mHidlSession_3_4->configureStreams_3_4(requestedConfiguration3_4, - [&status, &finalConfiguration3_4] + auto configStream34Cb = [&status, &finalConfiguration3_4] (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) { finalConfiguration3_4 = halConfiguration; status = s; - }); - if (!err.isOk()) { - ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); - return DEAD_OBJECT; + }; + + auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4] + (hardware::Return& err) -> status_t { + if (!err.isOk()) { + ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); + return DEAD_OBJECT; + } + finalConfiguration.streams.resize(finalConfiguration3_4.streams.size()); + for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) { + finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3; + } + return OK; + }; + + // See if we have v3.4 or v3.3 HAL + if (mHidlSession_3_5 != nullptr) { + ALOGV("%s: v3.5 device found", __FUNCTION__); + device::V3_5::StreamConfiguration requestedConfiguration3_5; + requestedConfiguration3_5.v3_4 = requestedConfiguration3_4; + requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++; + auto err = mHidlSession_3_5->configureStreams_3_5( + requestedConfiguration3_5, configStream34Cb); + res = postprocConfigStream34(err); + if (res != OK) { + return res; } - finalConfiguration.streams.resize(finalConfiguration3_4.streams.size()); - for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) { - finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3; + } else if (mHidlSession_3_4 != nullptr) { + // We do; use v3.4 for the call + ALOGV("%s: v3.4 device found", __FUNCTION__); + device::V3_4::HalStreamConfiguration finalConfiguration3_4; + auto err = mHidlSession_3_4->configureStreams_3_4( + requestedConfiguration3_4, configStream34Cb); + res = postprocConfigStream34(err); + if (res != OK) { + return res; } } else if (mHidlSession_3_3 != nullptr) { // We do; use v3.3 for the call @@ -4292,6 +4330,20 @@ status_t Camera3Device::HalInterface::close() { return res; } +void Camera3Device::HalInterface::signalPipelineDrain(const std::vector& streamIds) { + ATRACE_NAME("CameraHal::signalPipelineDrain"); + if (!valid() || mHidlSession_3_5 == nullptr) { + ALOGE("%s called on invalid camera!", __FUNCTION__); + return; + } + + auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter); + if (!err.isOk()) { + ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str()); + return; + } +} + void Camera3Device::HalInterface::getInflightBufferKeys( std::vector>* out) { std::lock_guard lock(mInflightLock); @@ -4418,6 +4470,7 @@ Camera3Device::RequestThread::RequestThread(wp parent, mReconfigured(false), mDoPause(false), mPaused(true), + mNotifyPipelineDrain(false), mFrameNumber(0), mLatestRequestId(NAME_NOT_FOUND), mCurrentAfTriggerId(0), @@ -5369,6 +5422,21 @@ bool Camera3Device::RequestThread::isOutputSurfacePending(int streamId, size_t s return false; } +void Camera3Device::RequestThread::signalPipelineDrain(const std::vector& streamIds) { + if (!mUseHalBufManager) { + ALOGE("%s called for camera device not supporting HAL buffer management", __FUNCTION__); + return; + } + + Mutex::Autolock pl(mPauseLock); + if (mPaused) { + return mInterface->signalPipelineDrain(streamIds); + } + // If request thread is still busy, wait until paused then notify HAL + mNotifyPipelineDrain = true; + mStreamIdsToBeDrained = streamIds; +} + nsecs_t Camera3Device::getExpectedInFlightDuration() { ATRACE_CALL(); Mutex::Autolock al(mInFlightLock); @@ -5546,6 +5614,11 @@ sp if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); } + if (mNotifyPipelineDrain) { + mInterface->signalPipelineDrain(mStreamIdsToBeDrained); + mNotifyPipelineDrain = false; + mStreamIdsToBeDrained.clear(); + } } // Stop waiting for now and let thread management happen return NULL; @@ -5630,6 +5703,11 @@ bool Camera3Device::RequestThread::waitIfPaused() { if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); } + if (mNotifyPipelineDrain) { + mInterface->signalPipelineDrain(mStreamIdsToBeDrained); + mNotifyPipelineDrain = false; + mStreamIdsToBeDrained.clear(); + } } res = mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 4ed6d9dd6b..5c0f570ad8 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -285,6 +285,8 @@ class Camera3Device : status_t dump(int fd); status_t close(); + void signalPipelineDrain(const std::vector& streamIds); + // method to extract buffer's unique ID // return pair of (newlySeenBuffer?, bufferId) std::pair getBufferId(const buffer_handle_t& buf, int streamId); @@ -372,6 +374,8 @@ class Camera3Device : // Buffers given to HAL through requestStreamBuffer API std::mutex mRequestedBuffersLock; std::unordered_map mRequestedBuffers; + + uint32_t mNextStreamConfigCounter = 1; }; sp mInterface; @@ -415,6 +419,7 @@ class Camera3Device : // get by (underlying) vector index sp operator[] (size_t index); size_t size() const; + std::vector getStreamIds(); void clear(); private: @@ -808,6 +813,8 @@ class Camera3Device : mRequestLatency.dump(fd, name); } + void signalPipelineDrain(const std::vector& streamIds); + protected: virtual bool threadLoop(); @@ -917,12 +924,13 @@ class Camera3Device : bool mReconfigured; - // Used by waitIfPaused, waitForNextRequest, and waitUntilPaused + // Used by waitIfPaused, waitForNextRequest, waitUntilPaused, and signalPipelineDrain Mutex mPauseLock; bool mDoPause; Condition mDoPauseSignal; bool mPaused; - Condition mPausedSignal; + bool mNotifyPipelineDrain; + std::vector mStreamIdsToBeDrained; sp mPrevRequest; int32_t mPrevTriggers;