You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
9.4 KiB

/*
* 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 {
camera_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
using hardware::camera::device::V3_2::BufferStatus;
switch (status) {
case BufferStatus::OK: return CAMERA_BUFFER_STATUS_OK;
case BufferStatus::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
}
return CAMERA_BUFFER_STATUS_ERROR;
}
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