• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *    * Redistributions of source code must retain the above copyright
8 *      notice, this list of conditions and the following disclaimer.
9 *    * Redistributions in binary form must reproduce the above
10 *      copyright notice, this list of conditions and the following
11 *      disclaimer in the documentation and/or other materials provided
12 *      with the distribution.
13 *    * Neither the name of The Linux Foundation nor the names of its
14 *      contributors may be used to endorse or promote products derived
15 *      from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include <dlfcn.h>
31 #include "overlay.h"
32 #include "pipes/overlayGenPipe.h"
33 #include "mdp_version.h"
34 #include "qdMetaData.h"
35 
36 #ifdef USES_QSEED_SCALAR
37 #include <scale/scale.h>
38 using namespace scale;
39 #endif
40 
41 #define PIPE_DEBUG 0
42 
43 namespace overlay {
44 using namespace utils;
45 
46 
Overlay()47 Overlay::Overlay() {
48     int numPipes = qdutils::MDPVersion::getInstance().getTotalPipes();
49     PipeBook::NUM_PIPES = (numPipes <= utils::OV_MAX)? numPipes : utils::OV_MAX;
50     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
51         mPipeBook[i].init();
52     }
53 
54     mDumpStr[0] = '\0';
55     initScalar();
56     setDMAMultiplexingSupported();
57 }
58 
~Overlay()59 Overlay::~Overlay() {
60     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
61         mPipeBook[i].destroy();
62     }
63     destroyScalar();
64 }
65 
configBegin()66 void Overlay::configBegin() {
67     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
68         //Mark as available for this round.
69         PipeBook::resetUse(i);
70         PipeBook::resetAllocation(i);
71     }
72     mDumpStr[0] = '\0';
73 }
74 
configDone()75 void Overlay::configDone() {
76     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
77         if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) ||
78                     isSessionEnded((eDest)i)) {
79             //Forces UNSET on pipes, flushes rotator memory and session, closes
80             //fds
81             if(mPipeBook[i].valid()) {
82                 char str[32];
83                 snprintf(str, 32, "Unset=%s dpy=%d mix=%d; ",
84                         PipeBook::getDestStr((eDest)i),
85                         mPipeBook[i].mDisplay, mPipeBook[i].mMixer);
86 #if PIPE_DEBUG
87                 strlcat(mDumpStr, str, sizeof(mDumpStr));
88 #endif
89             }
90             mPipeBook[i].destroy();
91         }
92     }
93     dump();
94     PipeBook::save();
95 }
96 
getPipeId(utils::eDest dest)97 int Overlay::getPipeId(utils::eDest dest) {
98     return mPipeBook[(int)dest].mPipe->getPipeId();
99 }
100 
getDest(int pipeid)101 eDest Overlay::getDest(int pipeid) {
102     eDest dest = OV_INVALID;
103     // finding the dest corresponding to the given pipe
104     for(int i=0; i < PipeBook::NUM_PIPES; ++i) {
105         if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) {
106             return (eDest)i;
107         }
108     }
109     return dest;
110 }
111 
reservePipe(int pipeid)112 eDest Overlay::reservePipe(int pipeid) {
113     eDest dest = getDest(pipeid);
114     PipeBook::setAllocation((int)dest);
115     return dest;
116 }
117 
nextPipe(eMdpPipeType type,int dpy,int mixer)118 eDest Overlay::nextPipe(eMdpPipeType type, int dpy, int mixer) {
119     eDest dest = OV_INVALID;
120 
121     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
122         if( (type == OV_MDP_PIPE_ANY || //Pipe type match
123              type == PipeBook::getPipeType((eDest)i)) &&
124             (mPipeBook[i].mDisplay == DPY_UNUSED || //Free or same display
125              mPipeBook[i].mDisplay == dpy) &&
126             (mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer
127              mPipeBook[i].mMixer == mixer) &&
128             PipeBook::isNotAllocated(i) && //Free pipe
129             ( (sDMAMultiplexingSupported && dpy) ||
130               !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode
131                PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){
132               //DMA-Multiplexing is only supported for WB on 8x26
133             dest = (eDest)i;
134             PipeBook::setAllocation(i);
135             break;
136         }
137     }
138 
139     if(dest != OV_INVALID) {
140         int index = (int)dest;
141         mPipeBook[index].mDisplay = dpy;
142         mPipeBook[index].mMixer = mixer;
143         if(not mPipeBook[index].valid()) {
144             mPipeBook[index].mPipe = new GenericPipe(dpy);
145             mPipeBook[index].mSession = PipeBook::NONE;
146             char str[32];
147             snprintf(str, 32, "Set=%s dpy=%d mix=%d; ",
148                      PipeBook::getDestStr(dest), dpy, mixer);
149 #if PIPE_DEBUG
150             strlcat(mDumpStr, str, sizeof(mDumpStr));
151 #endif
152         }
153     } else {
154         ALOGD_IF(PIPE_DEBUG, "Pipe unavailable type=%d display=%d mixer=%d",
155                 (int)type, dpy, mixer);
156     }
157 
158     return dest;
159 }
160 
endAllSessions()161 void Overlay::endAllSessions() {
162     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
163         if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
164             mPipeBook[i].mSession = PipeBook::END;
165     }
166 }
167 
isPipeTypeAttached(eMdpPipeType type)168 bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
169     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
170         if(type == PipeBook::getPipeType((eDest)i) &&
171                 mPipeBook[i].mDisplay != DPY_UNUSED) {
172             return true;
173         }
174     }
175     return false;
176 }
177 
commit(utils::eDest dest)178 bool Overlay::commit(utils::eDest dest) {
179     bool ret = false;
180     int index = (int)dest;
181     validate(index);
182 
183     if(mPipeBook[index].mPipe->commit()) {
184         ret = true;
185         PipeBook::setUse((int)dest);
186     } else {
187         int dpy = mPipeBook[index].mDisplay;
188         for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
189             if (mPipeBook[i].mDisplay == dpy) {
190                 PipeBook::resetAllocation(i);
191                 PipeBook::resetUse(i);
192             }
193         }
194     }
195     return ret;
196 }
197 
queueBuffer(int fd,uint32_t offset,utils::eDest dest)198 bool Overlay::queueBuffer(int fd, uint32_t offset,
199         utils::eDest dest) {
200     int index = (int)dest;
201     bool ret = false;
202     validate(index);
203     //Queue only if commit() has succeeded (and the bit set)
204     if(PipeBook::isUsed((int)dest)) {
205         ret = mPipeBook[index].mPipe->queueBuffer(fd, offset);
206     }
207     return ret;
208 }
209 
setCrop(const utils::Dim & d,utils::eDest dest)210 void Overlay::setCrop(const utils::Dim& d,
211         utils::eDest dest) {
212     int index = (int)dest;
213     validate(index);
214     mPipeBook[index].mPipe->setCrop(d);
215 }
216 
setColor(const uint32_t color,utils::eDest dest)217 void Overlay::setColor(const uint32_t color,
218         utils::eDest dest) {
219     int index = (int)dest;
220     validate(index);
221     mPipeBook[index].mPipe->setColor(color);
222 }
223 
setPosition(const utils::Dim & d,utils::eDest dest)224 void Overlay::setPosition(const utils::Dim& d,
225         utils::eDest dest) {
226     int index = (int)dest;
227     validate(index);
228     mPipeBook[index].mPipe->setPosition(d);
229 }
230 
setTransform(const int orient,utils::eDest dest)231 void Overlay::setTransform(const int orient,
232         utils::eDest dest) {
233     int index = (int)dest;
234     validate(index);
235 
236     utils::eTransform transform =
237             static_cast<utils::eTransform>(orient);
238     mPipeBook[index].mPipe->setTransform(transform);
239 
240 }
241 
setSource(const utils::PipeArgs args,utils::eDest dest)242 void Overlay::setSource(const utils::PipeArgs args,
243         utils::eDest dest) {
244     int index = (int)dest;
245     validate(index);
246 
247     PipeArgs newArgs(args);
248     if(PipeBook::getPipeType(dest) == OV_MDP_PIPE_VG) {
249         setMdpFlags(newArgs.mdpFlags, OV_MDP_PIPE_SHARE);
250     } else {
251         clearMdpFlags(newArgs.mdpFlags, OV_MDP_PIPE_SHARE);
252     }
253 
254     if(PipeBook::getPipeType(dest) == OV_MDP_PIPE_DMA) {
255         setMdpFlags(newArgs.mdpFlags, OV_MDP_PIPE_FORCE_DMA);
256     } else {
257         clearMdpFlags(newArgs.mdpFlags, OV_MDP_PIPE_FORCE_DMA);
258     }
259 
260     mPipeBook[index].mPipe->setSource(newArgs);
261 }
262 
setVisualParams(const MetaData_t & metadata,utils::eDest dest)263 void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) {
264     int index = (int)dest;
265     validate(index);
266     mPipeBook[index].mPipe->setVisualParams(metadata);
267 }
268 
getInstance()269 Overlay* Overlay::getInstance() {
270     if(sInstance == NULL) {
271         sInstance = new Overlay();
272     }
273     return sInstance;
274 }
275 
276 // Clears any VG pipes allocated to the fb devices
277 // Generates a LUT for pipe types.
initOverlay()278 int Overlay::initOverlay() {
279     int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
280     int numPipesXType[OV_MDP_PIPE_ANY] = {0};
281     numPipesXType[OV_MDP_PIPE_RGB] =
282             qdutils::MDPVersion::getInstance().getRGBPipes();
283     numPipesXType[OV_MDP_PIPE_VG] =
284             qdutils::MDPVersion::getInstance().getVGPipes();
285     numPipesXType[OV_MDP_PIPE_DMA] =
286             qdutils::MDPVersion::getInstance().getDMAPipes();
287 
288     int index = 0;
289     for(int X = 0; X < (int)OV_MDP_PIPE_ANY; X++) { //iterate over types
290         for(int j = 0; j < numPipesXType[X]; j++) { //iterate over num
291             PipeBook::pipeTypeLUT[index] = (utils::eMdpPipeType)X;
292             index++;
293         }
294     }
295 
296     if (mdpVersion < qdutils::MDSS_V5 && mdpVersion != qdutils::MDP_V3_0_4) {
297         msmfb_mixer_info_req  req;
298         mdp_mixer_info *minfo = NULL;
299         char name[64];
300         int fd = -1;
301         for(int i = 0; i < MAX_FB_DEVICES; i++) {
302             snprintf(name, 64, FB_DEVICE_TEMPLATE, i);
303             ALOGD("initoverlay:: opening the device:: %s", name);
304             fd = ::open(name, O_RDWR, 0);
305             if(fd < 0) {
306                 ALOGE("cannot open framebuffer(%d)", i);
307                 return -1;
308             }
309             //Get the mixer configuration */
310             req.mixer_num = i;
311             if (ioctl(fd, MSMFB_MIXER_INFO, &req) == -1) {
312                 ALOGE("ERROR: MSMFB_MIXER_INFO ioctl failed");
313                 close(fd);
314                 return -1;
315             }
316             minfo = req.info;
317             for (int j = 0; j < req.cnt; j++) {
318                 ALOGD("ndx=%d num=%d z_order=%d", minfo->pndx, minfo->pnum,
319                       minfo->z_order);
320                 // except the RGB base layer with z_order of -1, clear any
321                 // other pipes connected to mixer.
322                 if((minfo->z_order) != -1) {
323                     int index = minfo->pndx;
324                     ALOGD("Unset overlay with index: %d at mixer %d", index, i);
325                     if(ioctl(fd, MSMFB_OVERLAY_UNSET, &index) == -1) {
326                         ALOGE("ERROR: MSMFB_OVERLAY_UNSET failed");
327                         close(fd);
328                         return -1;
329                     }
330                 }
331                 minfo++;
332             }
333             close(fd);
334             fd = -1;
335         }
336     }
337 
338     FILE *displayDeviceFP = NULL;
339     const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
340     char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
341     char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
342     const char *strDtvPanel = "dtv panel";
343     const char *strWbPanel = "writeback panel";
344 
345     for(int num = 1; num < MAX_FB_DEVICES; num++) {
346         snprintf (msmFbTypePath, sizeof(msmFbTypePath),
347                 "/sys/class/graphics/fb%d/msm_fb_type", num);
348         displayDeviceFP = fopen(msmFbTypePath, "r");
349 
350         if(displayDeviceFP){
351             fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
352                     displayDeviceFP);
353 
354             if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) {
355                 sDpyFbMap[DPY_EXTERNAL] = num;
356             } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) {
357                 sDpyFbMap[DPY_WRITEBACK] = num;
358             }
359 
360             fclose(displayDeviceFP);
361         }
362     }
363 
364     return 0;
365 }
366 
displayCommit(const int & fd)367 bool Overlay::displayCommit(const int& fd) {
368     utils::Dim roi;
369     return displayCommit(fd, roi);
370 }
371 
displayCommit(const int & fd,const utils::Dim & roi)372 bool Overlay::displayCommit(const int& fd, const utils::Dim& roi) {
373     //Commit
374     struct mdp_display_commit info;
375     memset(&info, 0, sizeof(struct mdp_display_commit));
376     info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
377     info.roi.x = roi.x;
378     info.roi.y = roi.y;
379     info.roi.w = roi.w;
380     info.roi.h = roi.h;
381 
382     if(!mdp_wrapper::displayCommit(fd, info)) {
383         ALOGE("%s: commit failed", __func__);
384         return false;
385     }
386     return true;
387 }
388 
dump() const389 void Overlay::dump() const {
390 #if PIPE_DEBUG
391     if(strlen(mDumpStr)) { //dump only on state change
392         ALOGD("%s\n", mDumpStr);
393     }
394 #endif
395 }
396 
getDump(char * buf,size_t len)397 void Overlay::getDump(char *buf, size_t len) {
398     int totalPipes = 0;
399     const char *str = "\nOverlay State\n\n";
400     strlcat(buf, str, len);
401     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
402         if(mPipeBook[i].valid()) {
403             mPipeBook[i].mPipe->getDump(buf, len);
404             char str[64] = {'\0'};
405             snprintf(str, 64, "Display=%d\n\n", mPipeBook[i].mDisplay);
406             strlcat(buf, str, len);
407             totalPipes++;
408         }
409     }
410     char str_pipes[64] = {'\0'};
411     snprintf(str_pipes, 64, "Pipes=%d\n\n", totalPipes);
412     strlcat(buf, str_pipes, len);
413 }
414 
clear(int dpy)415 void Overlay::clear(int dpy) {
416     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
417         if (mPipeBook[i].mDisplay == dpy) {
418             // Mark as available for this round
419             PipeBook::resetUse(i);
420             PipeBook::resetAllocation(i);
421         }
422     }
423 }
424 
validateAndSet(const int & dpy,const int & fbFd)425 bool Overlay::validateAndSet(const int& dpy, const int& fbFd) {
426     GenericPipe* pipeArray[PipeBook::NUM_PIPES];
427     memset(&pipeArray, 0, sizeof(pipeArray));
428 
429     int num = 0;
430     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
431         if(PipeBook::isUsed(i) && mPipeBook[i].valid() &&
432                 mPipeBook[i].mDisplay == dpy) {
433             pipeArray[num++] = mPipeBook[i].mPipe;
434         }
435     }
436 
437     //Protect against misbehaving clients
438     return num ? GenericPipe::validateAndSet(pipeArray, num, fbFd) : true;
439 }
440 
initScalar()441 void Overlay::initScalar() {
442 #ifdef USES_QSEED_SCALAR
443     if(sLibScaleHandle == NULL) {
444         sLibScaleHandle = dlopen("libscale.so", RTLD_NOW);
445     }
446 
447     if(sLibScaleHandle) {
448         if(sScale == NULL) {
449             Scale* (*getInstance)();
450             *(void **) &getInstance = dlsym(sLibScaleHandle, "getInstance");
451             if(getInstance) {
452                 sScale = getInstance();
453             }
454         }
455     }
456 #endif
457 }
458 
destroyScalar()459 void Overlay::destroyScalar() {
460 #ifdef USES_QSEED_SCALAR
461     if(sLibScaleHandle) {
462         if(sScale) {
463             void (*destroyInstance)(Scale*);
464             *(void **) &destroyInstance = dlsym(sLibScaleHandle,
465                     "destroyInstance");
466             if(destroyInstance) {
467                 destroyInstance(sScale);
468                 sScale = NULL;
469             }
470         }
471         dlclose(sLibScaleHandle);
472         sLibScaleHandle = NULL;
473     }
474 #endif
475 }
476 
init()477 void Overlay::PipeBook::init() {
478     mPipe = NULL;
479     mDisplay = DPY_UNUSED;
480     mMixer = MIXER_UNUSED;
481 }
482 
destroy()483 void Overlay::PipeBook::destroy() {
484     if(mPipe) {
485         delete mPipe;
486         mPipe = NULL;
487     }
488     mDisplay = DPY_UNUSED;
489     mMixer = MIXER_UNUSED;
490     mSession = NONE;
491 }
492 
493 Overlay* Overlay::sInstance = 0;
494 int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
495 int Overlay::sDMAMode = DMA_LINE_MODE;
496 bool Overlay::sDMAMultiplexingSupported = false;
497 int Overlay::PipeBook::NUM_PIPES = 0;
498 int Overlay::PipeBook::sPipeUsageBitmap = 0;
499 int Overlay::PipeBook::sLastUsageBitmap = 0;
500 int Overlay::PipeBook::sAllocatedBitmap = 0;
501 utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] =
502     {utils::OV_MDP_PIPE_ANY};
503 void *Overlay::sLibScaleHandle = NULL;
504 scale::Scale *Overlay::sScale = NULL;
505 
506 }; // namespace overlay
507