blob: dd4c29ad1f75dec3304cbe9143d6d2b53fe47739 [file] [log] [blame]
/*
* 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