When a rotator or mdp configuration for a display fails, reset the layer-to-rotator mappings for that display and reset the release fences for the rotator objects used for that display. Note: The rotator itself is offline and not tied to any mixer. It is from the mappings that we deduce which rotator object was used for layers of which display. Also we don't delete rotator objects held for a specific display, since during stability runs, failures could repeat each round and we end up allocating and deallocating memory unnecessarily. The rotator objects will be deleted automatically when not required anymore. Change-Id: I9a67f02574be30be3b96b3575f60530cb1c89e10
193 lines
5.0 KiB
C++
193 lines
5.0 KiB
C++
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
|
|
* Not a Contribution, Apache license notifications and license are retained
|
|
* for attribution purposes only.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "overlayRotator.h"
|
|
#include "overlayUtils.h"
|
|
#include "mdp_version.h"
|
|
#include "gr.h"
|
|
|
|
namespace ovutils = overlay::utils;
|
|
|
|
namespace overlay {
|
|
|
|
//============Rotator=========================
|
|
|
|
Rotator::~Rotator() {}
|
|
|
|
Rotator* Rotator::getRotator() {
|
|
int type = getRotatorHwType();
|
|
if(type == TYPE_MDP) {
|
|
return new MdpRot(); //will do reset
|
|
} else if(type == TYPE_MDSS) {
|
|
return new MdssRot();
|
|
} else {
|
|
ALOGE("%s Unknown h/w type %d", __FUNCTION__, type);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
uint32_t Rotator::calcOutputBufSize(const utils::Whf& destWhf) {
|
|
//dummy aligned w & h.
|
|
int alW = 0, alH = 0;
|
|
int halFormat = ovutils::getHALFormat(destWhf.format);
|
|
//A call into gralloc/memalloc
|
|
return getBufferSizeAndDimensions(
|
|
destWhf.w, destWhf.h, halFormat, alW, alH);
|
|
}
|
|
|
|
int Rotator::getRotatorHwType() {
|
|
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
|
|
if (mdpVersion == qdutils::MDSS_V5)
|
|
return TYPE_MDSS;
|
|
return TYPE_MDP;
|
|
}
|
|
|
|
|
|
//============RotMem=========================
|
|
|
|
bool RotMem::close() {
|
|
bool ret = true;
|
|
for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) {
|
|
// skip current, and if valid, close
|
|
if(m[i].valid()) {
|
|
if(m[i].close() == false) {
|
|
ALOGE("%s error in closing rot mem %d", __FUNCTION__, i);
|
|
ret = false;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
RotMem::Mem::Mem() : mCurrOffset(0) {
|
|
utils::memset0(mRotOffset);
|
|
for(int i = 0; i < ROT_NUM_BUFS; i++) {
|
|
mRelFence[i] = -1;
|
|
}
|
|
}
|
|
|
|
RotMem::Mem::~Mem() {
|
|
for(int i = 0; i < ROT_NUM_BUFS; i++) {
|
|
::close(mRelFence[i]);
|
|
mRelFence[i] = -1;
|
|
}
|
|
}
|
|
|
|
void RotMem::Mem::setReleaseFd(const int& fence) {
|
|
int ret = 0;
|
|
|
|
if(mRelFence[mCurrOffset] >= 0) {
|
|
//Wait for previous usage of this buffer to be over.
|
|
//Can happen if rotation takes > vsync and a fast producer. i.e queue
|
|
//happens in subsequent vsyncs either because content is 60fps or
|
|
//because the producer is hasty sometimes.
|
|
ret = sync_wait(mRelFence[mCurrOffset], 1000);
|
|
if(ret < 0) {
|
|
ALOGE("%s: sync_wait error!! error no = %d err str = %s",
|
|
__FUNCTION__, errno, strerror(errno));
|
|
}
|
|
::close(mRelFence[mCurrOffset]);
|
|
}
|
|
mRelFence[mCurrOffset] = fence;
|
|
}
|
|
|
|
void RotMem::Mem::resetReleaseFd() {
|
|
//Will wait for previous offline rotation to finish, close fence fd
|
|
//and reset
|
|
setReleaseFd(-1);
|
|
}
|
|
|
|
//============RotMgr=========================
|
|
|
|
RotMgr::RotMgr() {
|
|
for(int i = 0; i < MAX_ROT_SESS; i++) {
|
|
mRot[i] = 0;
|
|
}
|
|
mUseCount = 0;
|
|
mRotDevFd = -1;
|
|
}
|
|
|
|
RotMgr::~RotMgr() {
|
|
clear();
|
|
}
|
|
|
|
void RotMgr::configBegin() {
|
|
//Reset the number of objects used
|
|
mUseCount = 0;
|
|
}
|
|
|
|
void RotMgr::configDone() {
|
|
//Remove the top most unused objects. Videos come and go.
|
|
for(int i = mUseCount; i < MAX_ROT_SESS; i++) {
|
|
if(mRot[i]) {
|
|
delete mRot[i];
|
|
mRot[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rotator* RotMgr::getNext() {
|
|
//Return a rot object, creating one if necessary
|
|
overlay::Rotator *rot = NULL;
|
|
if(mUseCount >= MAX_ROT_SESS) {
|
|
ALOGE("%s, MAX rotator sessions reached", __func__);
|
|
} else {
|
|
if(mRot[mUseCount] == NULL)
|
|
mRot[mUseCount] = overlay::Rotator::getRotator();
|
|
rot = mRot[mUseCount++];
|
|
}
|
|
return rot;
|
|
}
|
|
|
|
void RotMgr::clear() {
|
|
//Brute force obj destruction, helpful in suspend.
|
|
for(int i = 0; i < MAX_ROT_SESS; i++) {
|
|
if(mRot[i]) {
|
|
delete mRot[i];
|
|
mRot[i] = 0;
|
|
}
|
|
}
|
|
mUseCount = 0;
|
|
::close(mRotDevFd);
|
|
mRotDevFd = -1;
|
|
}
|
|
|
|
void RotMgr::getDump(char *buf, size_t len) {
|
|
for(int i = 0; i < MAX_ROT_SESS; i++) {
|
|
if(mRot[i]) {
|
|
mRot[i]->getDump(buf, len);
|
|
}
|
|
}
|
|
char str[4] = {'\0'};
|
|
snprintf(str, 4, "\n");
|
|
strncat(buf, str, strlen(str));
|
|
}
|
|
|
|
int RotMgr::getRotDevFd() {
|
|
if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDSS) {
|
|
mRotDevFd = ::open("/dev/graphics/fb0", O_RDWR, 0);
|
|
if(mRotDevFd < 0) {
|
|
ALOGE("%s failed to open fb0", __FUNCTION__);
|
|
}
|
|
}
|
|
return mRotDevFd;
|
|
}
|
|
|
|
}
|