1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  * Copyright (c) 2010-2014, 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 <math.h>
21 #include "overlayUtils.h"
22 #include "overlayRotator.h"
23 #include "gr.h"
24 
25 namespace ovutils = overlay::utils;
26 
27 namespace overlay {
28 
MdpRot()29 MdpRot::MdpRot() {
30     reset();
31     init();
32 }
33 
~MdpRot()34 MdpRot::~MdpRot() { close(); }
35 
enabled() const36 bool MdpRot::enabled() const { return mRotImgInfo.enable; }
37 
setRotations(uint32_t r)38 void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
39 
getSrcMemId() const40 int MdpRot::getSrcMemId() const {
41     return mRotDataInfo.src.memory_id;
42 }
43 
getDstMemId() const44 int MdpRot::getDstMemId() const {
45     return mRotDataInfo.dst.memory_id;
46 }
47 
getSrcOffset() const48 uint32_t MdpRot::getSrcOffset() const {
49     return mRotDataInfo.src.offset;
50 }
51 
getDstOffset() const52 uint32_t MdpRot::getDstOffset() const {
53     return mRotDataInfo.dst.offset;
54 }
55 
getDstFormat() const56 uint32_t MdpRot::getDstFormat() const {
57     return mRotImgInfo.dst.format;
58 }
59 
60 //Added for completeness. Not expected to be called.
getDstWhf() const61 utils::Whf MdpRot::getDstWhf() const {
62     int alW = 0, alH = 0;
63     int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
64     getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
65             halFormat, alW, alH);
66     return utils::Whf(alW, alH, mRotImgInfo.dst.format);
67 }
68 
69 //Added for completeness. Not expected to be called.
getDstDimensions() const70 utils::Dim MdpRot::getDstDimensions() const {
71     int alW = 0, alH = 0;
72     int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
73     getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
74             halFormat, alW, alH);
75     return utils::Dim(0, 0, alW, alH);
76 }
77 
getSessId() const78 uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; }
79 
setDownscale(int ds)80 void MdpRot::setDownscale(int ds) {
81     if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
82         // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
83         // This is an undocumented MDP Rotator constraint.
84         mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
85     }
86     mRotImgInfo.downscale_ratio = ds;
87 }
88 
save()89 void MdpRot::save() {
90     mLSRotImgInfo = mRotImgInfo;
91 }
92 
rotConfChanged() const93 bool MdpRot::rotConfChanged() const {
94     // 0 means same
95     if(0 == ::memcmp(&mRotImgInfo, &mLSRotImgInfo,
96                 sizeof (msm_rotator_img_info))) {
97         return false;
98     }
99     return true;
100 }
101 
init()102 bool MdpRot::init()
103 {
104     if(!mFd.open(Res::rotPath, O_RDWR)){
105         ALOGE("MdpRot failed to init %s", Res::rotPath);
106         return false;
107     }
108     return true;
109 }
110 
setSource(const overlay::utils::Whf & awhf)111 void MdpRot::setSource(const overlay::utils::Whf& awhf) {
112     utils::Whf whf(awhf);
113     mRotImgInfo.src.format = whf.format;
114 
115     mRotImgInfo.src.width = whf.w;
116     mRotImgInfo.src.height = whf.h;
117 
118     mRotImgInfo.src_rect.w = whf.w;
119     mRotImgInfo.src_rect.h = whf.h;
120 
121     mRotImgInfo.dst.width = whf.w;
122     mRotImgInfo.dst.height = whf.h;
123 }
124 
setCrop(const utils::Dim &)125 void MdpRot::setCrop(const utils::Dim& /*crop*/) {
126     // NO-OP for non-mdss rotator due to possible h/w limitations
127 }
128 
setFlags(const utils::eMdpFlags & flags)129 void MdpRot::setFlags(const utils::eMdpFlags& flags) {
130     mRotImgInfo.secure = 0;
131     if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
132         mRotImgInfo.secure = 1;
133 }
134 
setTransform(const utils::eTransform & rot)135 void MdpRot::setTransform(const utils::eTransform& rot)
136 {
137     int r = utils::getMdpOrient(rot);
138     setRotations(r);
139     mOrientation = static_cast<utils::eTransform>(r);
140     ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
141 }
142 
doTransform()143 void MdpRot::doTransform() {
144     if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
145         utils::swap(mRotImgInfo.dst.width, mRotImgInfo.dst.height);
146 }
147 
commit()148 bool MdpRot::commit() {
149     doTransform();
150     if(rotConfChanged()) {
151         mRotImgInfo.enable = 1;
152         if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) {
153             ALOGE("MdpRot commit failed");
154             dump();
155             mRotImgInfo.enable = 0;
156             return false;
157         }
158         mRotDataInfo.session_id = mRotImgInfo.session_id;
159     }
160     return true;
161 }
162 
calcOutputBufSize()163 uint32_t MdpRot::calcOutputBufSize() {
164     ovutils::Whf destWhf(mRotImgInfo.dst.width,
165             mRotImgInfo.dst.height, mRotImgInfo.dst.format);
166     return Rotator::calcOutputBufSize(destWhf);
167 }
168 
open_i(uint32_t numbufs,uint32_t bufsz)169 bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz)
170 {
171     OvMem mem;
172 
173     OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
174 
175     if(!mem.open(numbufs, bufsz, mRotImgInfo.secure)){
176         ALOGE("%s: Failed to open", __func__);
177         mem.close();
178         return false;
179     }
180 
181     OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
182     OVASSERT(mem.getFD() != -1, "getFd is -1");
183 
184     mRotDataInfo.dst.memory_id = mem.getFD();
185     mRotDataInfo.dst.offset = 0;
186     mMem.mem = mem;
187     return true;
188 }
189 
close()190 bool MdpRot::close() {
191     bool success = true;
192     if(mFd.valid() && (getSessId() != 0)) {
193         if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) {
194             ALOGE("Mdp Rot error endRotator, fd=%d sessId=%u",
195                     mFd.getFD(), getSessId());
196             success = false;
197         }
198     }
199     if (!mFd.close()) {
200         ALOGE("Mdp Rot error closing fd");
201         success = false;
202     }
203     if (!mMem.close()) {
204         ALOGE("Mdp Rot error closing mem");
205         success = false;
206     }
207     reset();
208     return success;
209 }
210 
remap(uint32_t numbufs)211 bool MdpRot::remap(uint32_t numbufs) {
212     // if current size changed, remap
213     uint32_t opBufSize = calcOutputBufSize();
214     if(opBufSize == mMem.size()) {
215         ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
216         return true;
217     }
218 
219     if(!mMem.close()) {
220         ALOGE("%s error in closing prev rot mem", __FUNCTION__);
221         return false;
222     }
223 
224     ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
225 
226     if(!open_i(numbufs, opBufSize)) {
227         ALOGE("%s Error could not open", __FUNCTION__);
228         return false;
229     }
230 
231     for (uint32_t i = 0; i < numbufs; ++i) {
232         mMem.mRotOffset[i] = i * opBufSize;
233     }
234 
235     return true;
236 }
237 
reset()238 void MdpRot::reset() {
239     ovutils::memset0(mRotImgInfo);
240     ovutils::memset0(mLSRotImgInfo);
241     ovutils::memset0(mRotDataInfo);
242     ovutils::memset0(mMem.mRotOffset);
243     mMem.mCurrIndex = 0;
244     mOrientation = utils::OVERLAY_TRANSFORM_0;
245 }
246 
queueBuffer(int fd,uint32_t offset)247 bool MdpRot::queueBuffer(int fd, uint32_t offset) {
248     if(enabled() and (not isRotCached(fd,offset))) {
249         int prev_fd = getSrcMemId();
250         uint32_t prev_offset = getSrcOffset();
251 
252         mRotDataInfo.src.memory_id = fd;
253         mRotDataInfo.src.offset = offset;
254 
255         if(false == remap(RotMem::ROT_NUM_BUFS)) {
256             ALOGE("%s Remap failed, not queueing", __FUNCTION__);
257             return false;
258         }
259 
260         mRotDataInfo.dst.offset =
261                 mMem.mRotOffset[mMem.mCurrIndex];
262 
263         if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
264             ALOGE("MdpRot failed rotate");
265             dump();
266             mRotDataInfo.src.memory_id = prev_fd;
267             mRotDataInfo.src.offset = prev_offset;
268             return false;
269         }
270         save();
271         mMem.mCurrIndex =
272                 (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
273     }
274     return true;
275 }
276 
dump() const277 void MdpRot::dump() const {
278     ALOGE("== Dump MdpRot start ==");
279     mFd.dump();
280     mMem.mem.dump();
281     mdp_wrapper::dump("mRotImgInfo", mRotImgInfo);
282     mdp_wrapper::dump("mRotDataInfo", mRotDataInfo);
283     ALOGE("== Dump MdpRot end ==");
284 }
285 
getDump(char * buf,size_t len) const286 void MdpRot::getDump(char *buf, size_t len) const {
287     ovutils::getDump(buf, len, "MdpRotCtrl", mRotImgInfo);
288     ovutils::getDump(buf, len, "MdpRotData", mRotDataInfo);
289 }
290 
getDownscaleFactor(const int & src_w,const int & src_h,const int & dst_w,const int & dst_h,const uint32_t &,const bool &)291 int MdpRot::getDownscaleFactor(const int& src_w, const int& src_h,
292         const int& dst_w, const int& dst_h, const uint32_t& /*mdpFormat*/,
293         const bool& /*isInterlaced*/) {
294     int dscale_factor = utils::ROT_DS_NONE;
295     // We need this check to engage the rotator whenever possible to assist MDP
296     // in performing video downscale.
297     // This saves bandwidth and avoids causing the driver to make too many panel
298     // -mode switches between BLT (writeback) and non-BLT (Direct) modes.
299     // Use-case: Video playback [with downscaling and rotation].
300     if (dst_w && dst_h)
301     {
302         float fDscale =  (float)(src_w * src_h) / (float)(dst_w * dst_h);
303         uint32_t dscale = (int)sqrtf(fDscale);
304 
305         if(dscale < 2) {
306             // Down-scale to > 50% of orig.
307             dscale_factor = utils::ROT_DS_NONE;
308         } else if(dscale < 4) {
309             // Down-scale to between > 25% to <= 50% of orig.
310             dscale_factor = utils::ROT_DS_HALF;
311         } else if(dscale < 8) {
312             // Down-scale to between > 12.5% to <= 25% of orig.
313             dscale_factor = utils::ROT_DS_FOURTH;
314         } else {
315             // Down-scale to <= 12.5% of orig.
316             dscale_factor = utils::ROT_DS_EIGHTH;
317         }
318     }
319     return dscale_factor;
320 }
321 
322 } // namespace overlay
323