/* * 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 #include #include #include #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 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 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 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 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 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 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 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 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* 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(¤t_timestamp); if (res != OK) { ALOGE("%s: Getting current timestamp failed: %s(%d)", __FUNCTION__, strerror(-res), res); return; } std::unique_lock 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(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 lock(zsl_buffers_lock_); filled_zsl_buffers_[zsl_buffer.frame_number] = std::move(zsl_buffer); } void ZslBufferManager::ReturnZslBuffers(std::vector zsl_buffers) { ATRACE_CALL(); for (auto& zsl_buffer : zsl_buffers) { ReturnZslBuffer(std::move(zsl_buffer)); } } bool ZslBufferManager::IsPendingBufferEmpty() { std::lock_guard 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& buffers) { ATRACE_CALL(); std::lock_guard 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* buffers) { ATRACE_CALL(); if (buffers == nullptr) { ALOGE("%s: buffers is nullptr", __FUNCTION__); return BAD_VALUE; } std::lock_guard 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