| /* | 
 |  * Copyright (C) 2019 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #define LOG_TAG "Camera3-BufUtils" | 
 | #define ATRACE_TAG ATRACE_TAG_CAMERA | 
 | //#define LOG_NDEBUG 0 | 
 | //#define LOG_NNDEBUG 0  // Per-frame verbose logging | 
 |  | 
 | #include <inttypes.h> | 
 |  | 
 | #include <utils/Log.h> | 
 |  | 
 | #include "device3/BufferUtils.h" | 
 |  | 
 | namespace android { | 
 | namespace camera3 { | 
 |  | 
 | void BufferRecords::takeInflightBufferMap(BufferRecords& other) { | 
 |     std::lock_guard<std::mutex> oLock(other.mInflightLock); | 
 |     std::lock_guard<std::mutex> lock(mInflightLock); | 
 |     if (mInflightBufferMap.size() > 0) { | 
 |         ALOGE("%s: inflight map is set in non-empty state!", __FUNCTION__); | 
 |     } | 
 |     mInflightBufferMap = std::move(other.mInflightBufferMap); | 
 |     other.mInflightBufferMap.clear(); | 
 | } | 
 |  | 
 | void BufferRecords::takeRequestedBufferMap(BufferRecords& other) { | 
 |     std::lock_guard<std::mutex> oLock(other.mRequestedBuffersLock); | 
 |     std::lock_guard<std::mutex> lock(mRequestedBuffersLock); | 
 |     if (mRequestedBufferMap.size() > 0) { | 
 |         ALOGE("%s: requested buffer map is set in non-empty state!", __FUNCTION__); | 
 |     } | 
 |     mRequestedBufferMap = std::move(other.mRequestedBufferMap); | 
 |     other.mRequestedBufferMap.clear(); | 
 | } | 
 |  | 
 | void BufferRecords::takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams) { | 
 |     std::lock_guard<std::mutex> oLock(other.mBufferIdMapLock); | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     if (mBufferIdMaps.size() > 0) { | 
 |         ALOGE("%s: buffer ID map is set in non-empty state!", __FUNCTION__); | 
 |     } | 
 |     for (auto streamId : streams) { | 
 |         mBufferIdMaps.insert({streamId, std::move(other.mBufferIdMaps.at(streamId))}); | 
 |     } | 
 |     other.mBufferIdMaps.clear(); | 
 | } | 
 |  | 
 | std::pair<bool, uint64_t> BufferRecords::getBufferId( | 
 |         const buffer_handle_t& buf, int streamId) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |  | 
 |     BufferIdMap& bIdMap = mBufferIdMaps.at(streamId); | 
 |     auto it = bIdMap.find(buf); | 
 |     if (it == bIdMap.end()) { | 
 |         bIdMap[buf] = mNextBufferId++; | 
 |         ALOGV("stream %d now have %zu buffer caches, buf %p", | 
 |                 streamId, bIdMap.size(), buf); | 
 |         return std::make_pair(true, mNextBufferId - 1); | 
 |     } else { | 
 |         return std::make_pair(false, it->second); | 
 |     } | 
 | } | 
 |  | 
 | void BufferRecords::tryCreateBufferCache(int streamId) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     if (mBufferIdMaps.count(streamId) == 0) { | 
 |         mBufferIdMaps.emplace(streamId, BufferIdMap{}); | 
 |     } | 
 | } | 
 |  | 
 | void BufferRecords::removeInactiveBufferCaches(const std::set<int32_t>& activeStreams) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) { | 
 |         int streamId = it->first; | 
 |         bool active = activeStreams.count(streamId) > 0; | 
 |         if (!active) { | 
 |             it = mBufferIdMaps.erase(it); | 
 |         } else { | 
 |             ++it; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | uint64_t BufferRecords::removeOneBufferCache(int streamId, const native_handle_t* handle) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     uint64_t bufferId = BUFFER_ID_NO_BUFFER; | 
 |     auto mapIt = mBufferIdMaps.find(streamId); | 
 |     if (mapIt == mBufferIdMaps.end()) { | 
 |         // streamId might be from a deleted stream here | 
 |         ALOGI("%s: stream %d has been removed", | 
 |                 __FUNCTION__, streamId); | 
 |         return BUFFER_ID_NO_BUFFER; | 
 |     } | 
 |     BufferIdMap& bIdMap = mapIt->second; | 
 |     auto it = bIdMap.find(handle); | 
 |     if (it == bIdMap.end()) { | 
 |         ALOGW("%s: cannot find buffer %p in stream %d", | 
 |                 __FUNCTION__, handle, streamId); | 
 |         return BUFFER_ID_NO_BUFFER; | 
 |     } else { | 
 |         bufferId = it->second; | 
 |         bIdMap.erase(it); | 
 |         ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p", | 
 |                 __FUNCTION__, streamId, bIdMap.size(), handle); | 
 |     } | 
 |     return bufferId; | 
 | } | 
 |  | 
 | std::vector<uint64_t> BufferRecords::clearBufferCaches(int streamId) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     std::vector<uint64_t> ret; | 
 |     auto mapIt = mBufferIdMaps.find(streamId); | 
 |     if (mapIt == mBufferIdMaps.end()) { | 
 |         ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId); | 
 |         return ret; | 
 |     } | 
 |     BufferIdMap& bIdMap = mapIt->second; | 
 |     ret.reserve(bIdMap.size()); | 
 |     for (const auto& it : bIdMap) { | 
 |         ret.push_back(it.second); | 
 |     } | 
 |     bIdMap.clear(); | 
 |     return ret; | 
 | } | 
 |  | 
 | bool BufferRecords::isStreamCached(int streamId) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     return mBufferIdMaps.find(streamId) != mBufferIdMaps.end(); | 
 | } | 
 |  | 
 | bool BufferRecords::verifyBufferIds( | 
 |         int32_t streamId, std::vector<uint64_t>& bufIds) { | 
 |     std::lock_guard<std::mutex> lock(mBufferIdMapLock); | 
 |     camera3::BufferIdMap& bIdMap = mBufferIdMaps.at(streamId); | 
 |     if (bIdMap.size() != bufIds.size()) { | 
 |         ALOGE("%s: stream ID %d buffer cache number mismatch: %zu/%zu (service/HAL)", | 
 |                 __FUNCTION__, streamId, bIdMap.size(), bufIds.size()); | 
 |         return false; | 
 |     } | 
 |     std::vector<uint64_t> internalBufIds; | 
 |     internalBufIds.reserve(bIdMap.size()); | 
 |     for (const auto& pair : bIdMap) { | 
 |         internalBufIds.push_back(pair.second); | 
 |     } | 
 |     std::sort(bufIds.begin(), bufIds.end()); | 
 |     std::sort(internalBufIds.begin(), internalBufIds.end()); | 
 |     for (size_t i = 0; i < bufIds.size(); i++) { | 
 |         if (bufIds[i] != internalBufIds[i]) { | 
 |             ALOGE("%s: buffer cache mismatch! Service %" PRIu64 ", HAL %" PRIu64, | 
 |                     __FUNCTION__, internalBufIds[i], bufIds[i]); | 
 |             return false; | 
 |         } | 
 |     } | 
 |     return true; | 
 | } | 
 |  | 
 | void BufferRecords::getInflightBufferKeys( | 
 |         std::vector<std::pair<int32_t, int32_t>>* out) { | 
 |     std::lock_guard<std::mutex> lock(mInflightLock); | 
 |     out->clear(); | 
 |     out->reserve(mInflightBufferMap.size()); | 
 |     for (auto& pair : mInflightBufferMap) { | 
 |         uint64_t key = pair.first; | 
 |         int32_t streamId = key & 0xFFFFFFFF; | 
 |         int32_t frameNumber = (key >> 32) & 0xFFFFFFFF; | 
 |         out->push_back(std::make_pair(frameNumber, streamId)); | 
 |     } | 
 |     return; | 
 | } | 
 |  | 
 | status_t BufferRecords::pushInflightBuffer( | 
 |         int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) { | 
 |     std::lock_guard<std::mutex> lock(mInflightLock); | 
 |     uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId); | 
 |     mInflightBufferMap[key] = buffer; | 
 |     return OK; | 
 | } | 
 |  | 
 | status_t BufferRecords::popInflightBuffer( | 
 |         int32_t frameNumber, int32_t streamId, | 
 |         /*out*/ buffer_handle_t **buffer) { | 
 |     std::lock_guard<std::mutex> lock(mInflightLock); | 
 |  | 
 |     uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId); | 
 |     auto it = mInflightBufferMap.find(key); | 
 |     if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND; | 
 |     if (buffer != nullptr) { | 
 |         *buffer = it->second; | 
 |     } | 
 |     mInflightBufferMap.erase(it); | 
 |     return OK; | 
 | } | 
 |  | 
 | void BufferRecords::popInflightBuffers( | 
 |         const std::vector<std::pair<int32_t, int32_t>>& buffers) { | 
 |     for (const auto& pair : buffers) { | 
 |         int32_t frameNumber = pair.first; | 
 |         int32_t streamId = pair.second; | 
 |         popInflightBuffer(frameNumber, streamId, nullptr); | 
 |     } | 
 | } | 
 |  | 
 | status_t BufferRecords::pushInflightRequestBuffer( | 
 |         uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) { | 
 |     std::lock_guard<std::mutex> lock(mRequestedBuffersLock); | 
 |     auto pair = mRequestedBufferMap.insert({bufferId, {streamId, 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 BufferRecords::popInflightRequestBuffer( | 
 |         uint64_t bufferId, | 
 |         /*out*/ buffer_handle_t** buffer, | 
 |         /*optional out*/ int32_t* streamId) { | 
 |     if (buffer == nullptr) { | 
 |         ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer); | 
 |         return BAD_VALUE; | 
 |     } | 
 |     std::lock_guard<std::mutex> lock(mRequestedBuffersLock); | 
 |     auto it = mRequestedBufferMap.find(bufferId); | 
 |     if (it == mRequestedBufferMap.end()) { | 
 |         ALOGE("%s: bufId %" PRIu64 " is not inflight!", | 
 |                 __FUNCTION__, bufferId); | 
 |         return BAD_VALUE; | 
 |     } | 
 |     *buffer = it->second.second; | 
 |     if (streamId != nullptr) { | 
 |         *streamId = it->second.first; | 
 |     } | 
 |     mRequestedBufferMap.erase(it); | 
 |     return OK; | 
 | } | 
 |  | 
 | void BufferRecords::getInflightRequestBufferKeys( | 
 |         std::vector<uint64_t>* out) { | 
 |     std::lock_guard<std::mutex> lock(mRequestedBuffersLock); | 
 |     out->clear(); | 
 |     out->reserve(mRequestedBufferMap.size()); | 
 |     for (auto& pair : mRequestedBufferMap) { | 
 |         out->push_back(pair.first); | 
 |     } | 
 |     return; | 
 | } | 
 |  | 
 |  | 
 | } // camera3 | 
 | } // namespace android |