diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 53aee7e364..7d41256038 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,217 @@ 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; + 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(); + } + + 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; + } + + sp stream = mOutputStreams.get(buf.streamId); + if (stream == nullptr) { + ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId); + continue; + } + streamBuffer.stream = stream->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) { @@ -1067,21 +1284,32 @@ 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; - 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; @@ -1163,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; } @@ -1350,6 +1578,56 @@ 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(); +} + +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, @@ -1533,20 +1811,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; } @@ -1573,14 +1851,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) { @@ -1605,21 +1881,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 @@ -1863,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; @@ -2038,15 +2320,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; @@ -2066,15 +2345,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; @@ -2090,14 +2366,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; @@ -2156,12 +2429,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)); @@ -2206,10 +2478,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) { @@ -2219,7 +2491,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) ", @@ -2238,13 +2509,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); } @@ -2298,15 +2567,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()) { @@ -2367,7 +2633,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) { @@ -2502,7 +2768,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(); @@ -2560,8 +2826,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) { @@ -2668,15 +2933,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(); @@ -2943,12 +3205,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); } } @@ -3475,6 +3737,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; @@ -3651,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 @@ -4041,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); @@ -4081,6 +4384,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 +4459,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), @@ -4139,6 +4470,7 @@ Camera3Device::RequestThread::RequestThread(wp parent, mReconfigured(false), mDoPause(false), mPaused(true), + mNotifyPipelineDrain(false), mFrameNumber(0), mLatestRequestId(NAME_NOT_FOUND), mCurrentAfTriggerId(0), @@ -4149,7 +4481,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 +5261,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(); @@ -5078,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); @@ -5255,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; @@ -5339,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); @@ -5794,23 +6163,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..5c0f570ad8 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,27 @@ 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); + // 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 +313,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 +366,16 @@ 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; + + uint32_t mNextStreamConfigCounter = 1; }; sp mInterface; @@ -412,9 +410,22 @@ 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; + std::vector getStreamIds(); + void clear(); + + private: + mutable std::mutex mLock; + KeyedVector> mData; + }; StreamSet mOutputStreams; sp mInputStream; @@ -483,8 +494,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 +507,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 +723,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); @@ -790,6 +813,8 @@ class Camera3Device : mRequestLatency.dump(fd, name); } + void signalPipelineDrain(const std::vector& streamIds); + protected: virtual bool threadLoop(); @@ -899,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; @@ -937,6 +963,8 @@ class Camera3Device : Vector mSessionParamKeys; CameraMetadata mLatestSessionParams; + + const bool mUseHalBufManager; }; sp mRequestThread; @@ -1020,7 +1048,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 +1245,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 };