android13/hardware/google/camera/common/hal/utils/zsl_buffer_manager.cc

546 lines
18 KiB
C++

/*
* 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_NDEBUG 0
#define LOG_TAG "GCH_ZslBufferManager"
#define ATRACE_TAG ATRACE_TAG_CAMERA
#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Trace.h>
#include <time.h>
#include "zsl_buffer_manager.h"
namespace android {
namespace google_camera_hal {
ZslBufferManager::ZslBufferManager(IHalBufferAllocator* allocator,
int partial_result_count)
: kMemoryProfilingEnabled(
property_get_bool("persist.vendor.camera.hal.memoryprofile", false)),
buffer_allocator_(allocator),
partial_result_count_(partial_result_count) {
}
ZslBufferManager::~ZslBufferManager() {
ATRACE_CALL();
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
if (buffer_allocator_ != nullptr) {
buffer_allocator_->FreeBuffers(&buffers_);
}
}
status_t ZslBufferManager::AllocateBuffers(
const HalBufferDescriptor& buffer_descriptor) {
ATRACE_CALL();
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
if (allocated_) {
ALOGE("%s: Buffer is already allocated.", __FUNCTION__);
return ALREADY_EXISTS;
}
// Create a buffer allocator if the client doesn't specify one.
if (buffer_allocator_ == nullptr) {
// Create a buffer manager.
internal_buffer_allocator_ = GrallocBufferAllocator::Create();
if (internal_buffer_allocator_ == nullptr) {
ALOGE("%s: Creating a buffer manager failed.", __FUNCTION__);
return NO_MEMORY;
}
buffer_allocator_ = internal_buffer_allocator_.get();
}
uint32_t num_buffers = buffer_descriptor.immediate_num_buffers;
buffer_descriptor_ = buffer_descriptor;
status_t res = AllocateBuffersLocked(num_buffers);
if (res != OK) {
ALOGE("%s: Allocating %d buffers failed.", __FUNCTION__, num_buffers);
return res;
}
allocated_ = true;
return OK;
}
status_t ZslBufferManager::AllocateBuffersLocked(uint32_t buffer_number) {
if (buffer_number + buffers_.size() > buffer_descriptor_.max_num_buffers) {
ALOGE("%s: allocate %d + exist %zu > max buffer number %d", __FUNCTION__,
buffer_number, buffers_.size(), buffer_descriptor_.max_num_buffers);
return NO_MEMORY;
}
HalBufferDescriptor buffer_descriptor = buffer_descriptor_;
buffer_descriptor.immediate_num_buffers = buffer_number;
std::vector<buffer_handle_t> buffers;
status_t res = buffer_allocator_->AllocateBuffers(buffer_descriptor, &buffers);
if (res != OK) {
ALOGE("%s: AllocateBuffers fail.", __FUNCTION__);
return res;
}
for (auto& buffer : buffers) {
if (buffer != kInvalidBufferHandle) {
buffers_.push_back(buffer);
empty_zsl_buffers_.push_back(buffer);
}
}
if (buffers.size() != buffer_number) {
ALOGE("%s: allocate buffer failed. request %u, get %zu", __FUNCTION__,
buffer_number, buffers.size());
return NO_MEMORY;
}
if (kMemoryProfilingEnabled) {
ALOGI(
"%s: Allocated %u buffers, res %ux%u, format %d, overall allocated "
"%zu buffers",
__FUNCTION__, buffer_number, buffer_descriptor_.width,
buffer_descriptor_.height, buffer_descriptor_.format, buffers_.size());
}
return OK;
}
buffer_handle_t ZslBufferManager::GetEmptyBuffer() {
ATRACE_CALL();
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
if (!allocated_) {
ALOGE("%s: Buffers are not allocated.", __FUNCTION__);
return kInvalidBufferHandle;
}
buffer_handle_t buffer = GetEmptyBufferLocked();
if (buffer == kInvalidBufferHandle) {
// Try to allocate one more buffer if there is no empty buffer.
status_t res = AllocateBuffersLocked(/*buffer_number=*/1);
if (res != OK) {
ALOGE("%s: Allocating one more buffer failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return kInvalidBufferHandle;
}
buffer = GetEmptyBufferLocked();
}
return buffer;
}
buffer_handle_t ZslBufferManager::GetEmptyBufferLocked() {
ATRACE_CALL();
buffer_handle_t buffer = kInvalidBufferHandle;
// Get an empty buffer from empty ZSL buffer queue.
// If empty ZSL buffer queue is empty,
// Get the oldest buffer from filled ZSL buffer queue.
// If filled ZSL buffer queue is empty,
// Get the oldest buffer from the partially filled ZSL buffer queue.
if (empty_zsl_buffers_.size() > 0) {
buffer = empty_zsl_buffers_[0];
empty_zsl_buffers_.pop_front();
} else if (filled_zsl_buffers_.size() > 0) {
auto buffer_iter = filled_zsl_buffers_.begin();
buffer = buffer_iter->second.buffer.buffer;
filled_zsl_buffers_.erase(buffer_iter);
} else if (partially_filled_zsl_buffers_.size() > 0) {
auto buffer_iter = partially_filled_zsl_buffers_.begin();
while (buffer_iter != partially_filled_zsl_buffers_.end()) {
if (buffer_iter->second.partial_result == partial_result_count_) {
if (buffer_iter->second.buffer.buffer != kInvalidBufferHandle) {
ALOGE("%s: Invalid: both are ready in partial zsl queue.",
__FUNCTION__);
// TODO: clean up resources in this invalid situation.
return kInvalidBufferHandle;
}
ALOGI(
"%s: Remove metadata-only buffer in partially filled zsl "
"buffer queue. Releasing the metadata resource.",
__FUNCTION__);
} else if (buffer_iter->second.buffer.buffer == kInvalidBufferHandle &&
buffer_iter->second.partial_result == 0) {
ALOGE(
"%s: Invalid: both buffer and metadata are empty in partial "
"zsl queue.",
__FUNCTION__);
// TODO: clean up resources in this invalid situation.
return kInvalidBufferHandle;
} else {
ALOGI(
"%s: Get buffer-only empty buffer from partially filled zsl "
"buffer queue.",
__FUNCTION__);
buffer = buffer_iter->second.buffer.buffer;
}
// remove whatever visited
buffer_iter = partially_filled_zsl_buffers_.erase(buffer_iter);
if (buffer != kInvalidBufferHandle) {
break;
}
}
if (buffer_iter == partially_filled_zsl_buffers_.end()) {
ALOGE("%s: No empty buffer available.", __FUNCTION__);
}
} else {
ALOGW("%s: No empty buffer available.", __FUNCTION__);
}
return buffer;
}
void ZslBufferManager::FreeUnusedBuffersLocked() {
ATRACE_CALL();
if (empty_zsl_buffers_.size() <= kMaxUnusedBuffers ||
buffers_.size() <= buffer_descriptor_.immediate_num_buffers) {
idle_buffer_frame_counter_ = 0;
return;
}
idle_buffer_frame_counter_++;
if (idle_buffer_frame_counter_ <= kMaxIdelBufferFrameCounter) {
return;
}
std::vector<buffer_handle_t> unused_buffers;
// When there are at least kMaxUnusedBuffers unused buffers, try to reduce
// the number of buffers to buffer_descriptor_.immediate_num_buffers.
while (buffers_.size() > buffer_descriptor_.immediate_num_buffers &&
empty_zsl_buffers_.size() > 0) {
buffer_handle_t buffer = empty_zsl_buffers_.back();
unused_buffers.push_back(buffer);
empty_zsl_buffers_.pop_back();
buffers_.erase(std::find(buffers_.begin(), buffers_.end(), buffer));
}
if (kMemoryProfilingEnabled) {
ALOGI(
"%s: Freeing %zu buffers, res %ux%u, format %d, overall allocated "
"%zu buffers",
__FUNCTION__, unused_buffers.size(), buffer_descriptor_.width,
buffer_descriptor_.height, buffer_descriptor_.format, buffers_.size());
}
buffer_allocator_->FreeBuffers(&unused_buffers);
}
status_t ZslBufferManager::ReturnEmptyBuffer(buffer_handle_t buffer) {
ATRACE_CALL();
if (buffer == kInvalidBufferHandle) {
ALOGE("%s: buffer is nullptr.", __FUNCTION__);
return BAD_VALUE;
}
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
// Check whether the returned buffer is freed or not
auto exist_buffer = std::find(buffers_.begin(), buffers_.end(), buffer);
if (exist_buffer == buffers_.end()) {
ALOGE("%s: Buffer %p is invalid", __FUNCTION__, buffer);
return BAD_VALUE;
}
auto empty_buffer = std::find(std::begin(empty_zsl_buffers_),
std::end(empty_zsl_buffers_), buffer);
if (empty_buffer != std::end(empty_zsl_buffers_)) {
ALOGE("%s: Buffer %p was already returned.", __FUNCTION__, buffer);
return ALREADY_EXISTS;
}
empty_zsl_buffers_.push_back(buffer);
FreeUnusedBuffersLocked();
return OK;
}
status_t ZslBufferManager::ReturnFilledBuffer(uint32_t frame_number,
const StreamBuffer& buffer) {
ATRACE_CALL();
ZslBuffer zsl_buffer = {};
zsl_buffer.frame_number = frame_number;
zsl_buffer.buffer = buffer;
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
if (partially_filled_zsl_buffers_.empty() ||
partially_filled_zsl_buffers_.find(frame_number) ==
partially_filled_zsl_buffers_.end()) {
// not able to distinguish these two cases through the current status
// of the partial buffer
ALOGV(
"%s: no entry for frame[%u] in ZslBufferManager. Not created or "
"has been removed",
__FUNCTION__, frame_number);
zsl_buffer.metadata = nullptr;
partially_filled_zsl_buffers_[frame_number] = std::move(zsl_buffer);
} else if (partially_filled_zsl_buffers_[frame_number].buffer.buffer ==
kInvalidBufferHandle) {
partially_filled_zsl_buffers_[frame_number].buffer = buffer;
if (partially_filled_zsl_buffers_[frame_number].partial_result ==
partial_result_count_) {
ALOGV(
"%s: both buffer and metadata for frame[%u] are ready. Move to "
"filled_zsl_buffers_.",
__FUNCTION__, frame_number);
filled_zsl_buffers_[frame_number] =
std::move(partially_filled_zsl_buffers_[frame_number]);
partially_filled_zsl_buffers_.erase(frame_number);
}
} else {
ALOGE(
"%s: the buffer for frame[%u] already returned or the metadata is "
"missing.",
__FUNCTION__, frame_number);
return INVALID_OPERATION;
}
return OK;
}
status_t ZslBufferManager::ReturnMetadata(uint32_t frame_number,
const HalCameraMetadata* metadata,
int partial_result) {
ATRACE_CALL();
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
ZslBuffer zsl_buffer = {};
zsl_buffer.frame_number = frame_number;
zsl_buffer.partial_result = partial_result;
auto partially_filled_buffer_it =
partially_filled_zsl_buffers_.find(frame_number);
if (partially_filled_buffer_it == partially_filled_zsl_buffers_.end()) {
// not able to distinguish these two cases through the current status of
// the partial buffer
ALOGV(
"%s: no entry for frame[%u] in ZslBufferManager. Not created or "
"has been removed",
__FUNCTION__, frame_number);
zsl_buffer.buffer = {};
zsl_buffer.metadata = HalCameraMetadata::Clone(metadata);
if (zsl_buffer.metadata == nullptr) {
ALOGE("%s: Failed to Clone camera metadata.", __FUNCTION__);
return NO_MEMORY;
}
partially_filled_zsl_buffers_[frame_number] = std::move(zsl_buffer);
} else if (partial_result < partial_result_count_) {
partially_filled_buffer_it->second.partial_result = partial_result;
// Need to wait for more partial results
if (partially_filled_buffer_it->second.metadata == nullptr) {
// This is the first partial result, clone to create an entry
partially_filled_buffer_it->second.metadata =
HalCameraMetadata::Clone(metadata);
if (partially_filled_buffer_it->second.metadata == nullptr) {
ALOGE("%s: Failed to Clone camera metadata.", __FUNCTION__);
return NO_MEMORY;
}
} else {
// Append to previously received partial results
partially_filled_buffer_it->second.metadata->Append(
metadata->GetRawCameraMetadata());
}
} else {
zsl_buffer.buffer = partially_filled_buffer_it->second.buffer;
partially_filled_buffer_it->second.partial_result = partial_result;
if (partially_filled_buffer_it->second.metadata == nullptr) {
// This will happen if partial_result_count_ == 1
partially_filled_buffer_it->second.metadata =
HalCameraMetadata::Clone(metadata);
} else {
// This is the last partial result, append it to the others
partially_filled_buffer_it->second.metadata->Append(
metadata->GetRawCameraMetadata());
}
if (partially_filled_buffer_it->second.buffer.buffer !=
kInvalidBufferHandle) {
ALOGV(
"%s: both buffer and metadata for frame[%u] are ready. Move to "
"filled_zsl_buffers_.",
__FUNCTION__, frame_number);
filled_zsl_buffers_[frame_number] =
std::move(partially_filled_buffer_it->second);
partially_filled_zsl_buffers_.erase(frame_number);
}
}
if (partially_filled_zsl_buffers_.size() > kMaxPartialZslBuffers) {
// Remove the oldest one if it exceeds the maximum number of partial ZSL
// buffers.
partially_filled_zsl_buffers_.erase(partially_filled_zsl_buffers_.begin());
}
return OK;
}
status_t ZslBufferManager::GetCurrentTimestampNs(int64_t* current_timestamp) {
if (current_timestamp == nullptr) {
ALOGE("%s: current_timestamp is nullptr", __FUNCTION__);
return BAD_VALUE;
}
struct timespec ts;
if (clock_gettime(CLOCK_BOOTTIME, &ts)) {
ALOGE("%s: Getting boot time failed.", __FUNCTION__);
return UNKNOWN_ERROR;
}
static const int64_t kNsPerSec = 1000000000;
*current_timestamp = ts.tv_sec * kNsPerSec + ts.tv_nsec;
return OK;
}
void ZslBufferManager::GetMostRecentZslBuffers(
std::vector<ZslBuffer>* zsl_buffers, uint32_t num_buffers,
uint32_t min_buffers) {
ATRACE_CALL();
if (zsl_buffers == nullptr) {
return;
}
int64_t current_timestamp;
status_t res = GetCurrentTimestampNs(&current_timestamp);
if (res != OK) {
ALOGE("%s: Getting current timestamp failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return;
}
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
if (filled_zsl_buffers_.size() < min_buffers) {
ALOGD("%s: Requested min_buffers = %u, ZslBufferManager only has %zu",
__FUNCTION__, min_buffers, filled_zsl_buffers_.size());
ALOGD("%s: Not enough ZSL buffers to get, returns empty zsl_buffers.",
__FUNCTION__);
return;
}
num_buffers =
std::min(static_cast<uint32_t>(filled_zsl_buffers_.size()), num_buffers);
auto zsl_buffer_iter = filled_zsl_buffers_.begin();
// Skip the older ones.
for (uint32_t i = 0; i < filled_zsl_buffers_.size() - num_buffers; i++) {
zsl_buffer_iter++;
}
// Fallback to realtime pipeline capture if there are any flash-fired frame
// in zsl buffers with AE_MODE_ON_AUTO_FLASH.
camera_metadata_ro_entry entry = {};
res = zsl_buffer_iter->second.metadata->Get(ANDROID_CONTROL_AE_MODE, &entry);
if (res == OK && entry.data.u8[0] == ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH) {
for (auto search_iter = filled_zsl_buffers_.begin();
search_iter != filled_zsl_buffers_.end(); search_iter++) {
res = search_iter->second.metadata->Get(ANDROID_FLASH_STATE, &entry);
if (res == OK && entry.count == 1) {
if (entry.data.u8[0] == ANDROID_FLASH_STATE_FIRED) {
ALOGD("%s: Returns empty zsl_buffers due to flash fired",
__FUNCTION__);
return;
}
}
}
}
for (uint32_t i = 0; i < num_buffers; i++) {
camera_metadata_ro_entry entry = {};
int64_t buffer_timestamp;
res =
zsl_buffer_iter->second.metadata->Get(ANDROID_SENSOR_TIMESTAMP, &entry);
if (res != OK || entry.count != 1) {
ALOGW("%s: Getting sensor timestamp failed: %s(%d)", __FUNCTION__,
strerror(-res), res);
return;
}
buffer_timestamp = entry.data.i64[0];
// Only include recent buffers.
if (current_timestamp - buffer_timestamp < kMaxBufferTimestampDiff) {
zsl_buffers->push_back(std::move(zsl_buffer_iter->second));
zsl_buffer_iter = filled_zsl_buffers_.erase(zsl_buffer_iter);
} else {
zsl_buffer_iter++;
}
}
}
void ZslBufferManager::ReturnZslBuffer(ZslBuffer zsl_buffer) {
ATRACE_CALL();
std::unique_lock<std::mutex> lock(zsl_buffers_lock_);
filled_zsl_buffers_[zsl_buffer.frame_number] = std::move(zsl_buffer);
}
void ZslBufferManager::ReturnZslBuffers(std::vector<ZslBuffer> zsl_buffers) {
ATRACE_CALL();
for (auto& zsl_buffer : zsl_buffers) {
ReturnZslBuffer(std::move(zsl_buffer));
}
}
bool ZslBufferManager::IsPendingBufferEmpty() {
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
bool empty = (pending_zsl_buffers_.size() == 0);
if (!empty) {
ALOGW("%s: Pending buffer is not empty:%zu.", __FUNCTION__,
pending_zsl_buffers_.size());
return false;
}
return true;
}
void ZslBufferManager::AddPendingBuffers(const std::vector<ZslBuffer>& buffers) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
for (auto& buffer : buffers) {
ZslBuffer zsl_buffer = {
.frame_number = buffer.frame_number,
.buffer = buffer.buffer,
.metadata = HalCameraMetadata::Clone(buffer.metadata.get()),
};
pending_zsl_buffers_.emplace(buffer.buffer.buffer, std::move(zsl_buffer));
}
}
status_t ZslBufferManager::CleanPendingBuffers(std::vector<ZslBuffer>* buffers) {
ATRACE_CALL();
if (buffers == nullptr) {
ALOGE("%s: buffers is nullptr", __FUNCTION__);
return BAD_VALUE;
}
std::lock_guard<std::mutex> lock(pending_zsl_buffers_mutex);
if (pending_zsl_buffers_.empty()) {
ALOGE("%s: There is no empty buffer.", __FUNCTION__);
return BAD_VALUE;
}
for (auto zsl_buffer_iter = pending_zsl_buffers_.begin();
zsl_buffer_iter != pending_zsl_buffers_.end(); zsl_buffer_iter++) {
buffers->push_back(std::move(zsl_buffer_iter->second));
}
pending_zsl_buffers_.clear();
return OK;
}
} // namespace google_camera_hal
} // namespace android