Files
android_vendor_qcom_opensou…/liboverlay/overlayMdpRot.cpp
Raj Kamal bd3bdc6d03 hwc/overlay: Implement rotator caching
* A non-updating layer requiring rotation, can make use of
the older rotator buffer written when the layer got first
updated, rather than invoking a new rotator cycle.

* A rotator play is avoided in cases where incoming layer
buffer fd, offset, whf, src-rect, dst-rect, etc are similar
to that of the previous input layer to the rotator.

* For ex: In a usecase where video layer updates happen at
30fps and all other asynchrous UI updates happen at 60fps,
instead of the traditional 60 calls of rotator play per sec,
we now do only 30 thereby saving rotator bandwidth.

* Property "debug.rotcache.disable" can be used to disable
this feature.

Change-Id: I1d1c352c63007b7e0b4fee40882086ccd2f5a4aa
2014-08-13 01:31:49 -07:00

323 lines
9.2 KiB
C++
Executable File

/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2014, 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 <math.h>
#include "overlayUtils.h"
#include "overlayRotator.h"
#include "gr.h"
namespace ovutils = overlay::utils;
namespace overlay {
MdpRot::MdpRot() {
reset();
init();
}
MdpRot::~MdpRot() { close(); }
bool MdpRot::enabled() const { return mRotImgInfo.enable; }
void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
int MdpRot::getSrcMemId() const {
return mRotDataInfo.src.memory_id;
}
int MdpRot::getDstMemId() const {
return mRotDataInfo.dst.memory_id;
}
uint32_t MdpRot::getSrcOffset() const {
return mRotDataInfo.src.offset;
}
uint32_t MdpRot::getDstOffset() const {
return mRotDataInfo.dst.offset;
}
uint32_t MdpRot::getDstFormat() const {
return mRotImgInfo.dst.format;
}
//Added for completeness. Not expected to be called.
utils::Whf MdpRot::getDstWhf() const {
int alW = 0, alH = 0;
int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
halFormat, alW, alH);
return utils::Whf(alW, alH, mRotImgInfo.dst.format);
}
//Added for completeness. Not expected to be called.
utils::Dim MdpRot::getDstDimensions() const {
int alW = 0, alH = 0;
int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
halFormat, alW, alH);
return utils::Dim(0, 0, alW, alH);
}
uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; }
void MdpRot::setDownscale(int ds) {
if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
// Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
// This is an undocumented MDP Rotator constraint.
mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
}
mRotImgInfo.downscale_ratio = ds;
}
void MdpRot::save() {
mLSRotImgInfo = mRotImgInfo;
}
bool MdpRot::rotConfChanged() const {
// 0 means same
if(0 == ::memcmp(&mRotImgInfo, &mLSRotImgInfo,
sizeof (msm_rotator_img_info))) {
return false;
}
return true;
}
bool MdpRot::init()
{
if(!mFd.open(Res::rotPath, O_RDWR)){
ALOGE("MdpRot failed to init %s", Res::rotPath);
return false;
}
return true;
}
void MdpRot::setSource(const overlay::utils::Whf& awhf) {
utils::Whf whf(awhf);
mRotImgInfo.src.format = whf.format;
mRotImgInfo.src.width = whf.w;
mRotImgInfo.src.height = whf.h;
mRotImgInfo.src_rect.w = whf.w;
mRotImgInfo.src_rect.h = whf.h;
mRotImgInfo.dst.width = whf.w;
mRotImgInfo.dst.height = whf.h;
}
void MdpRot::setCrop(const utils::Dim& /*crop*/) {
// NO-OP for non-mdss rotator due to possible h/w limitations
}
void MdpRot::setFlags(const utils::eMdpFlags& flags) {
mRotImgInfo.secure = 0;
if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
mRotImgInfo.secure = 1;
}
void MdpRot::setTransform(const utils::eTransform& rot)
{
int r = utils::getMdpOrient(rot);
setRotations(r);
mOrientation = static_cast<utils::eTransform>(r);
ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
}
void MdpRot::doTransform() {
if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
utils::swap(mRotImgInfo.dst.width, mRotImgInfo.dst.height);
}
bool MdpRot::commit() {
doTransform();
if(rotConfChanged()) {
mRotImgInfo.enable = 1;
if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) {
ALOGE("MdpRot commit failed");
dump();
mRotImgInfo.enable = 0;
return false;
}
mRotDataInfo.session_id = mRotImgInfo.session_id;
}
return true;
}
uint32_t MdpRot::calcOutputBufSize() {
ovutils::Whf destWhf(mRotImgInfo.dst.width,
mRotImgInfo.dst.height, mRotImgInfo.dst.format);
return Rotator::calcOutputBufSize(destWhf);
}
bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz)
{
OvMem mem;
OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
if(!mem.open(numbufs, bufsz, mRotImgInfo.secure)){
ALOGE("%s: Failed to open", __func__);
mem.close();
return false;
}
OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
OVASSERT(mem.getFD() != -1, "getFd is -1");
mRotDataInfo.dst.memory_id = mem.getFD();
mRotDataInfo.dst.offset = 0;
mMem.mem = mem;
return true;
}
bool MdpRot::close() {
bool success = true;
if(mFd.valid() && (getSessId() != 0)) {
if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) {
ALOGE("Mdp Rot error endRotator, fd=%d sessId=%u",
mFd.getFD(), getSessId());
success = false;
}
}
if (!mFd.close()) {
ALOGE("Mdp Rot error closing fd");
success = false;
}
if (!mMem.close()) {
ALOGE("Mdp Rot error closing mem");
success = false;
}
reset();
return success;
}
bool MdpRot::remap(uint32_t numbufs) {
// if current size changed, remap
uint32_t opBufSize = calcOutputBufSize();
if(opBufSize == mMem.size()) {
ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
return true;
}
if(!mMem.close()) {
ALOGE("%s error in closing prev rot mem", __FUNCTION__);
return false;
}
ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
if(!open_i(numbufs, opBufSize)) {
ALOGE("%s Error could not open", __FUNCTION__);
return false;
}
for (uint32_t i = 0; i < numbufs; ++i) {
mMem.mRotOffset[i] = i * opBufSize;
}
return true;
}
void MdpRot::reset() {
ovutils::memset0(mRotImgInfo);
ovutils::memset0(mLSRotImgInfo);
ovutils::memset0(mRotDataInfo);
ovutils::memset0(mMem.mRotOffset);
mMem.mCurrIndex = 0;
mOrientation = utils::OVERLAY_TRANSFORM_0;
}
bool MdpRot::queueBuffer(int fd, uint32_t offset) {
if(enabled() and (not isRotCached(fd,offset))) {
int prev_fd = getSrcMemId();
uint32_t prev_offset = getSrcOffset();
mRotDataInfo.src.memory_id = fd;
mRotDataInfo.src.offset = offset;
if(false == remap(RotMem::ROT_NUM_BUFS)) {
ALOGE("%s Remap failed, not queueing", __FUNCTION__);
return false;
}
mRotDataInfo.dst.offset =
mMem.mRotOffset[mMem.mCurrIndex];
if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
ALOGE("MdpRot failed rotate");
dump();
mRotDataInfo.src.memory_id = prev_fd;
mRotDataInfo.src.offset = prev_offset;
return false;
}
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
}
return true;
}
void MdpRot::dump() const {
ALOGE("== Dump MdpRot start ==");
mFd.dump();
mMem.mem.dump();
mdp_wrapper::dump("mRotImgInfo", mRotImgInfo);
mdp_wrapper::dump("mRotDataInfo", mRotDataInfo);
ALOGE("== Dump MdpRot end ==");
}
void MdpRot::getDump(char *buf, size_t len) const {
ovutils::getDump(buf, len, "MdpRotCtrl", mRotImgInfo);
ovutils::getDump(buf, len, "MdpRotData", mRotDataInfo);
}
int MdpRot::getDownscaleFactor(const int& src_w, const int& src_h,
const int& dst_w, const int& dst_h, const uint32_t& /*mdpFormat*/,
const bool& /*isInterlaced*/) {
int dscale_factor = utils::ROT_DS_NONE;
// We need this check to engage the rotator whenever possible to assist MDP
// in performing video downscale.
// This saves bandwidth and avoids causing the driver to make too many panel
// -mode switches between BLT (writeback) and non-BLT (Direct) modes.
// Use-case: Video playback [with downscaling and rotation].
if (dst_w && dst_h)
{
float fDscale = (float)(src_w * src_h) / (float)(dst_w * dst_h);
uint32_t dscale = (int)sqrtf(fDscale);
if(dscale < 2) {
// Down-scale to > 50% of orig.
dscale_factor = utils::ROT_DS_NONE;
} else if(dscale < 4) {
// Down-scale to between > 25% to <= 50% of orig.
dscale_factor = utils::ROT_DS_HALF;
} else if(dscale < 8) {
// Down-scale to between > 12.5% to <= 25% of orig.
dscale_factor = utils::ROT_DS_FOURTH;
} else {
// Down-scale to <= 12.5% of orig.
dscale_factor = utils::ROT_DS_EIGHTH;
}
}
return dscale_factor;
}
} // namespace overlay