1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. 4 * Not a Contribution, Apache license notifications and license are retained 5 * for attribution purposes only. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18*/ 19 20#include "overlayUtils.h" 21#include "overlayRotator.h" 22 23#define DEBUG_MDSS_ROT 0 24 25#ifdef VENUS_COLOR_FORMAT 26#include <media/msm_media_info.h> 27#else 28#define VENUS_BUFFER_SIZE(args...) 0 29#endif 30 31#ifndef MDSS_MDP_ROT_ONLY 32#define MDSS_MDP_ROT_ONLY 0x80 33#endif 34 35#define SIZE_1M 0x00100000 36#define MDSS_ROT_MASK (MDP_ROT_90 | MDP_FLIP_UD | MDP_FLIP_LR) 37 38namespace ovutils = overlay::utils; 39 40namespace overlay { 41MdssRot::MdssRot() { 42 reset(); 43 init(); 44} 45 46MdssRot::~MdssRot() { close(); } 47 48bool MdssRot::enabled() const { return mEnabled; } 49 50void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; } 51 52int MdssRot::getDstMemId() const { 53 return mRotData.dst_data.memory_id; 54} 55 56uint32_t MdssRot::getDstOffset() const { 57 return mRotData.dst_data.offset; 58} 59 60uint32_t MdssRot::getDstFormat() const { 61 //For mdss src and dst formats are same 62 return mRotInfo.src.format; 63} 64 65uint32_t MdssRot::getSessId() const { return mRotInfo.id; } 66 67bool MdssRot::init() { 68 if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) { 69 ALOGE("MdssRot failed to init fb0"); 70 return false; 71 } 72 return true; 73} 74 75void MdssRot::setSource(const overlay::utils::Whf& awhf) { 76 utils::Whf whf(awhf); 77 78 mRotInfo.src.format = whf.format; 79 mRotInfo.src.width = whf.w; 80 mRotInfo.src.height = whf.h; 81} 82 83void MdssRot::setCrop(const utils::Dim& crop) { 84 85 mRotInfo.src_rect.x = crop.x; 86 mRotInfo.src_rect.y = crop.y; 87 mRotInfo.src_rect.w = crop.w; 88 mRotInfo.src_rect.h = crop.h; 89 90 mRotInfo.dst_rect.x = 0; 91 mRotInfo.dst_rect.y = 0; 92 mRotInfo.dst_rect.w = crop.w; 93 mRotInfo.dst_rect.h = crop.h; 94} 95 96void MdssRot::setDownscale(int ds) {} 97 98void MdssRot::setFlags(const utils::eMdpFlags& flags) { 99 mRotInfo.flags = flags; 100} 101 102void MdssRot::setTransform(const utils::eTransform& rot) 103{ 104 // reset rotation flags to avoid stale orientation values 105 mRotInfo.flags &= ~MDSS_ROT_MASK; 106 int flags = utils::getMdpOrient(rot); 107 if (flags != -1) 108 setRotations(flags); 109 mOrientation = static_cast<utils::eTransform>(flags); 110 ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags); 111} 112 113void MdssRot::doTransform() { 114 mRotInfo.flags |= mOrientation; 115 if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90) 116 utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h); 117} 118 119bool MdssRot::commit() { 120 doTransform(); 121 mRotInfo.flags |= MDSS_MDP_ROT_ONLY; 122 mEnabled = true; 123 if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) { 124 ALOGE("MdssRot commit failed!"); 125 dump(); 126 return (mEnabled = false); 127 } 128 mRotData.id = mRotInfo.id; 129 return true; 130} 131 132bool MdssRot::queueBuffer(int fd, uint32_t offset) { 133 if(enabled()) { 134 mRotData.data.memory_id = fd; 135 mRotData.data.offset = offset; 136 137 remap(RotMem::Mem::ROT_NUM_BUFS); 138 OVASSERT(mMem.curr().m.numBufs(), "queueBuffer numbufs is 0"); 139 140 mRotData.dst_data.offset = 141 mMem.curr().mRotOffset[mMem.curr().mCurrOffset]; 142 mMem.curr().mCurrOffset = 143 (mMem.curr().mCurrOffset + 1) % mMem.curr().m.numBufs(); 144 145 if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) { 146 ALOGE("MdssRot play failed!"); 147 dump(); 148 return false; 149 } 150 151 // if the prev mem is valid, we need to close 152 if(mMem.prev().valid()) { 153 // FIXME if no wait for vsync the above 154 // play will return immediatly and might cause 155 // tearing when prev.close is called. 156 if(!mMem.prev().close()) { 157 ALOGE("%s error in closing prev rot mem", __FUNCTION__); 158 return false; 159 } 160 } 161 } 162 return true; 163} 164 165bool MdssRot::open_i(uint32_t numbufs, uint32_t bufsz) 166{ 167 OvMem mem; 168 OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i"); 169 bool isSecure = mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION; 170 171 if(!mem.open(numbufs, bufsz, isSecure)){ 172 ALOGE("%s: Failed to open", __func__); 173 mem.close(); 174 return false; 175 } 176 177 OVASSERT(MAP_FAILED != mem.addr(), "MAP failed"); 178 OVASSERT(mem.getFD() != -1, "getFd is -1"); 179 180 mRotData.dst_data.memory_id = mem.getFD(); 181 mRotData.dst_data.offset = 0; 182 mMem.curr().m = mem; 183 return true; 184} 185 186bool MdssRot::remap(uint32_t numbufs) { 187 // Calculate the size based on rotator's dst format, w and h. 188 uint32_t opBufSize = calcOutputBufSize(); 189 // If current size changed, remap 190 if(opBufSize == mMem.curr().size()) { 191 ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize); 192 return true; 193 } 194 195 ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__); 196 OVASSERT(!mMem.prev().valid(), "Prev should not be valid"); 197 198 // ++mMem will make curr to be prev, and prev will be curr 199 ++mMem; 200 if(!open_i(numbufs, opBufSize)) { 201 ALOGE("%s Error could not open", __FUNCTION__); 202 return false; 203 } 204 for (uint32_t i = 0; i < numbufs; ++i) { 205 mMem.curr().mRotOffset[i] = i * opBufSize; 206 } 207 return true; 208} 209 210bool MdssRot::close() { 211 bool success = true; 212 if(mFd.valid() && (getSessId() != (uint32_t) MSMFB_NEW_REQUEST)) { 213 if(!mdp_wrapper::unsetOverlay(mFd.getFD(), getSessId())) { 214 ALOGE("MdssRot::close unsetOverlay failed, fd=%d sessId=%d", 215 mFd.getFD(), getSessId()); 216 success = false; 217 } 218 } 219 220 if (!mFd.close()) { 221 ALOGE("Mdss Rot error closing fd"); 222 success = false; 223 } 224 if (!mMem.close()) { 225 ALOGE("Mdss Rot error closing mem"); 226 success = false; 227 } 228 reset(); 229 return success; 230} 231 232void MdssRot::reset() { 233 ovutils::memset0(mRotInfo); 234 ovutils::memset0(mRotData); 235 mRotData.data.memory_id = -1; 236 mRotInfo.id = MSMFB_NEW_REQUEST; 237 ovutils::memset0(mMem.curr().mRotOffset); 238 ovutils::memset0(mMem.prev().mRotOffset); 239 mMem.curr().mCurrOffset = 0; 240 mMem.prev().mCurrOffset = 0; 241 mOrientation = utils::OVERLAY_TRANSFORM_0; 242} 243 244void MdssRot::dump() const { 245 ALOGE("== Dump MdssRot start =="); 246 mFd.dump(); 247 mMem.curr().m.dump(); 248 mdp_wrapper::dump("mRotInfo", mRotInfo); 249 mdp_wrapper::dump("mRotData", mRotData); 250 ALOGE("== Dump MdssRot end =="); 251} 252 253uint32_t MdssRot::calcOutputBufSize() { 254 uint32_t opBufSize = 0; 255 ovutils::Whf destWhf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h, 256 mRotInfo.src.format); //mdss src and dst formats are same. 257 258 if (mRotInfo.flags & ovutils::OV_MDSS_MDP_BWC_EN) { 259 opBufSize = calcCompressedBufSize(destWhf); 260 } else { 261 opBufSize = Rotator::calcOutputBufSize(destWhf); 262 } 263 264 if (mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION) 265 opBufSize = utils::align(opBufSize, SIZE_1M); 266 267 return opBufSize; 268} 269 270void MdssRot::getDump(char *buf, size_t len) const { 271 ovutils::getDump(buf, len, "MdssRotCtrl", mRotInfo); 272 ovutils::getDump(buf, len, "MdssRotData", mRotData); 273} 274 275// Calculate the compressed o/p buffer size for BWC 276uint32_t MdssRot::calcCompressedBufSize(const ovutils::Whf& destWhf) { 277 uint32_t bufSize = 0; 278 int aWidth = ovutils::align(destWhf.w, 64); 279 int aHeight = ovutils::align(destWhf.h, 4); 280 int rau_cnt = aWidth/64; 281 int stride0 = (64 * 4 * rau_cnt) + rau_cnt/8; 282 int stride1 = ((64 * 2 * rau_cnt) + rau_cnt/8) * 2; 283 int stride0_off = (aHeight/4); 284 int stride1_off = (aHeight/2); 285 286 //New o/p size for BWC 287 bufSize = (stride0 * stride0_off + stride1 * stride1_off) + 288 (rau_cnt * 2 * (stride0_off + stride1_off)); 289 ALOGD_IF(DEBUG_MDSS_ROT, "%s: width = %d, height = %d raucount = %d" 290 "opBufSize = %d ", __FUNCTION__, aWidth, aHeight, rau_cnt, bufSize); 291 return bufSize; 292} 293 294} // namespace overlay 295