| /* |
| * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <utils/debug.h> |
| #include <utils/constants.h> |
| #include <sys/mman.h> |
| #include <fcntl.h> |
| |
| #include "session_manager.h" |
| #include "hw_rotator_interface.h" |
| |
| #define __CLASS__ "SessionManager" |
| |
| namespace sde { |
| |
| // SessionManager State Transition |
| // ******************************************************* |
| // Current State * Next State |
| // ***************************************** |
| // * RELEASED READY ACQUIRED |
| // ******************************************************* |
| // RELEASED * NA NA OpenSession() |
| // READY * Stop() NA OpenSession() |
| // ACQUIRED * NA Start() NA |
| //******************************************************** |
| |
| // ------------------------------- SessionManager Implementation ----------------------------------- |
| |
| SessionManager::SessionManager(HWRotatorInterface *hw_rotator_intf, |
| BufferAllocator *buffer_allocator, |
| BufferSyncHandler *buffer_sync_handler) |
| : hw_rotator_intf_(hw_rotator_intf), buffer_allocator_(buffer_allocator), |
| buffer_sync_handler_(buffer_sync_handler), active_session_count_(0) { |
| } |
| |
| void SessionManager::Start(const int &client_id) { |
| SCOPE_LOCK(locker_); |
| |
| uint32_t session_count = 0; |
| uint32_t acquired_session_count = 0; |
| |
| // Change the state of acquired session to kSessionReady |
| while ((acquired_session_count < active_session_count_) && (session_count < kMaxSessionCount)) { |
| if (session_list_[session_count].state == kSessionAcquired) { |
| if (session_list_[session_count].client_id == client_id) { |
| session_list_[session_count].state = kSessionReady; |
| } |
| acquired_session_count++; |
| } |
| session_count++; |
| } |
| } |
| |
| DisplayError SessionManager::OpenSession(const int &client_id, |
| HWRotatorSession *hw_rotator_session) { |
| SCOPE_LOCK(locker_); |
| |
| DisplayError error = kErrorNone; |
| |
| const HWSessionConfig &input_config = hw_rotator_session->hw_session_config; |
| |
| DLOGI_IF(kTagRotator, "Src buffer: width = %d, height = %d, format = %d", |
| input_config.src_width, input_config.src_height, input_config.src_format); |
| DLOGI_IF(kTagRotator, "Dst buffer: width = %d, height = %d, format = %d", |
| input_config.dst_width, input_config.dst_height, input_config.dst_format); |
| DLOGI_IF(kTagRotator, "buffer_count = %d, secure = %d, cache = %d, frame_rate = %d", |
| input_config.buffer_count, input_config.secure, input_config.cache, |
| input_config.frame_rate); |
| |
| uint32_t free_session = active_session_count_; |
| uint32_t acquired_session = kMaxSessionCount; |
| uint32_t active_session_count = 0; |
| |
| // First look for a session in ready state, if no session found in ready state matching |
| // with current input session config, assign a session in released state. |
| for (uint32_t session_count = 0; session_count < kMaxSessionCount && |
| active_session_count < active_session_count_; session_count++) { |
| HWSessionConfig &hw_session_config = |
| session_list_[session_count].hw_rotator_session.hw_session_config; |
| |
| if (session_list_[session_count].state == kSessionReleased) { |
| free_session = session_count; |
| continue; |
| } |
| |
| if (session_list_[session_count].state == kSessionReady) { |
| if (session_list_[session_count].client_id == client_id && |
| input_config == hw_session_config) { |
| session_list_[session_count].state = kSessionAcquired; |
| acquired_session = session_count; |
| break; |
| } |
| } |
| active_session_count++; |
| } |
| |
| // If the input config does not match with existing config, then add new session and change the |
| // state to kSessionAcquired |
| if (acquired_session == kMaxSessionCount) { |
| if (free_session >= kMaxSessionCount) { |
| return kErrorMemory; |
| } |
| |
| error = AcquireSession(hw_rotator_session, &session_list_[free_session]); |
| if (error !=kErrorNone) { |
| return error; |
| } |
| |
| acquired_session = free_session; |
| hw_rotator_session->session_id = acquired_session; |
| session_list_[acquired_session].client_id = client_id; |
| active_session_count_++; |
| |
| DLOGV_IF(kTagRotator, "Acquire new session Output: width = %d, height = %d, format = %d, " \ |
| "session_id %d, client_id %d", hw_rotator_session->output_buffer.width, |
| hw_rotator_session->output_buffer.height, hw_rotator_session->output_buffer.format, |
| hw_rotator_session->session_id, client_id); |
| |
| return kErrorNone; |
| } |
| |
| *hw_rotator_session = session_list_[acquired_session].hw_rotator_session; |
| |
| DLOGV_IF(kTagRotator, "Acquire existing session Output: width = %d, height = %d, format = %d, " \ |
| "session_id %d, client_id %d", hw_rotator_session->output_buffer.width, |
| hw_rotator_session->output_buffer.height, hw_rotator_session->output_buffer.format, |
| hw_rotator_session->session_id, client_id); |
| |
| return kErrorNone; |
| } |
| |
| DisplayError SessionManager::GetNextBuffer(const int &client_id, |
| HWRotatorSession *hw_rotator_session) { |
| SCOPE_LOCK(locker_); |
| |
| DisplayError error = kErrorNone; |
| |
| int session_id = hw_rotator_session->session_id; |
| if (session_id > kMaxSessionCount) { |
| return kErrorParameters; |
| } |
| |
| Session *session = &session_list_[session_id]; |
| if (session->state != kSessionAcquired) { |
| DLOGE("Invalid session state %d", session->state); |
| return kErrorParameters; |
| } |
| |
| uint32_t curr_index = session->curr_index; |
| |
| BufferInfo *buffer_info = &session->buffer_info; |
| if (buffer_info->alloc_buffer_info.fd < 0) { |
| const uint32_t &buffer_count = buffer_info->buffer_config.buffer_count; |
| const size_t &buffer_size = buffer_info->alloc_buffer_info.size; |
| |
| error = buffer_allocator_->AllocateBuffer(buffer_info); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| for (uint32_t idx = 0; idx < buffer_count; idx++) { |
| session->offset[idx] = UINT32((buffer_size / buffer_count) * idx); |
| } |
| } |
| |
| // Wait for the release fence fd before the session being given to the client. |
| buffer_sync_handler_->SyncWait(session->release_fd[curr_index]); |
| close(session->release_fd[curr_index]); |
| session->release_fd[curr_index] = -1; |
| |
| hw_rotator_session->output_buffer.planes[0].stride = buffer_info->alloc_buffer_info.stride; |
| hw_rotator_session->output_buffer.planes[0].fd = buffer_info->alloc_buffer_info.fd; |
| hw_rotator_session->output_buffer.planes[0].offset = session->offset[curr_index]; |
| |
| session->hw_rotator_session = *hw_rotator_session; |
| |
| DLOGI_IF(kTagRotator, "Output: width = %d, height = %d, format = %d, stride %d, " \ |
| "curr_index = %d, offset %d, fd %d, session_id %d, client_id %d", |
| hw_rotator_session->output_buffer.width, hw_rotator_session->output_buffer.height, |
| hw_rotator_session->output_buffer.format, |
| hw_rotator_session->output_buffer.planes[0].stride, curr_index, |
| hw_rotator_session->output_buffer.planes[0].offset, |
| hw_rotator_session->output_buffer.planes[0].fd, session_id, client_id); |
| |
| return kErrorNone; |
| } |
| |
| DisplayError SessionManager::Stop(const int &client_id) { |
| SCOPE_LOCK(locker_); |
| |
| DisplayError error = kErrorNone; |
| uint32_t session_id = 0; |
| |
| // Release all the sessions which were not acquired in the current cycle and deallocate the |
| // buffers associated with it. |
| while ((active_session_count_ > 0) && (session_id < kMaxSessionCount)) { |
| if (session_list_[session_id].state == kSessionReady && |
| session_list_[session_id].client_id == client_id) { |
| error = ReleaseSession(&session_list_[session_id]); |
| if (error != kErrorNone) { |
| return error; |
| } |
| active_session_count_--; |
| |
| DLOGI_IF(kTagRotator, "session_id = %d, active_session_count = %d, client_id %d", session_id, |
| active_session_count_, client_id); |
| } |
| session_id++; |
| } |
| |
| return kErrorNone; |
| } |
| |
| DisplayError SessionManager::SetReleaseFd(const int &client_id, |
| HWRotatorSession *hw_rotator_session) { |
| SCOPE_LOCK(locker_); |
| |
| int session_id = hw_rotator_session->session_id; |
| if (session_id > kMaxSessionCount) { |
| return kErrorParameters; |
| } |
| |
| Session *session = &session_list_[session_id]; |
| if (session->state != kSessionAcquired) { |
| DLOGE("Invalid session state %d", session->state); |
| return kErrorParameters; |
| } |
| |
| uint32_t &curr_index = session->curr_index; |
| uint32_t buffer_count = hw_rotator_session->hw_session_config.buffer_count; |
| |
| // 1. Store the release fence fd, so that session manager waits for the release fence fd |
| // to be signaled and populates the session info to the client. |
| // 2. Modify the curr_index to point to next buffer. |
| session->release_fd[curr_index] = hw_rotator_session->output_buffer.release_fence_fd; |
| |
| curr_index = (curr_index + 1) % buffer_count; |
| |
| DLOGI_IF(kTagRotator, "session_id %d, curr_index = %d, release fd %d, client_id %d", session_id, |
| curr_index, hw_rotator_session->output_buffer.release_fence_fd, client_id); |
| |
| return kErrorNone; |
| } |
| |
| DisplayError SessionManager::AcquireSession(HWRotatorSession *hw_rotator_session, |
| Session *session) { |
| DisplayError error = kErrorNone; |
| const HWSessionConfig &input_config = hw_rotator_session->hw_session_config; |
| |
| error = hw_rotator_intf_->OpenSession(hw_rotator_session); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| hw_rotator_session->output_buffer = LayerBuffer(); |
| hw_rotator_session->output_buffer.width = input_config.dst_width; |
| hw_rotator_session->output_buffer.height = input_config.dst_height; |
| hw_rotator_session->output_buffer.format = input_config.dst_format; |
| hw_rotator_session->output_buffer.flags.secure = input_config.secure; |
| |
| uint32_t buffer_count = hw_rotator_session->hw_session_config.buffer_count; |
| |
| session->release_fd = new int[buffer_count]; |
| if (session->release_fd == NULL) { |
| return kErrorMemory; |
| } |
| |
| session->offset = new uint32_t[buffer_count]; |
| if (session->offset == NULL) { |
| delete[] session->release_fd; |
| session->release_fd = NULL; |
| return kErrorMemory; |
| } |
| |
| for (uint32_t idx = 0; idx < buffer_count; idx++) { |
| session->release_fd[idx] = -1; |
| session->offset[idx] = 0; |
| } |
| session->curr_index = 0; |
| |
| session->hw_rotator_session = HWRotatorSession(); |
| session->buffer_info = BufferInfo(); |
| |
| BufferInfo *buffer_info = &session->buffer_info; |
| buffer_info->buffer_config.buffer_count = hw_rotator_session->hw_session_config.buffer_count; |
| buffer_info->buffer_config.secure = hw_rotator_session->hw_session_config.secure; |
| buffer_info->buffer_config.cache = hw_rotator_session->hw_session_config.cache; |
| buffer_info->buffer_config.width = hw_rotator_session->hw_session_config.dst_width; |
| buffer_info->buffer_config.height = hw_rotator_session->hw_session_config.dst_height; |
| buffer_info->buffer_config.format = hw_rotator_session->hw_session_config.dst_format; |
| |
| session->state = kSessionAcquired; |
| session->hw_rotator_session = *hw_rotator_session; |
| |
| return kErrorNone; |
| } |
| |
| DisplayError SessionManager::ReleaseSession(Session *session) { |
| DisplayError error = kErrorNone; |
| |
| BufferInfo *buffer_info = &session->buffer_info; |
| |
| error = buffer_allocator_->FreeBuffer(buffer_info); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| error = hw_rotator_intf_->CloseSession(&session->hw_rotator_session); |
| if (error != kErrorNone) { |
| return error; |
| } |
| |
| uint32_t buffer_count = buffer_info->buffer_config.buffer_count; |
| |
| for (uint32_t idx = 0; idx < buffer_count; idx++) { |
| if (session->release_fd[idx] >= 0) { |
| close(session->release_fd[idx]); |
| session->release_fd[idx] = -1; |
| } |
| } |
| |
| session->state = kSessionReleased; |
| session->client_id == -1; |
| |
| if (session->offset) { |
| delete[] session->offset; |
| session->offset = NULL; |
| } |
| |
| if (session->release_fd) { |
| delete[] session->release_fd; |
| session->release_fd = NULL; |
| } |
| |
| return kErrorNone; |
| } |
| |
| } // namespace sde |