1 /*
2 * Copyright (c) 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 
31 #define DEBUG 0
32 #include <ctype.h>
33 #include <fcntl.h>
34 #include <media/IAudioPolicyService.h>
35 #include <media/AudioSystem.h>
36 #include <utils/threads.h>
37 #include <utils/Errors.h>
38 #include <utils/Log.h>
39 
40 #include <linux/msm_mdp.h>
41 #include <linux/fb.h>
42 #include <sys/ioctl.h>
43 #include <sys/poll.h>
44 #include <sys/resource.h>
45 #include <cutils/properties.h>
46 #include "hwc_utils.h"
47 #include "virtual.h"
48 #include "overlayUtils.h"
49 #include "overlay.h"
50 #include "mdp_version.h"
51 
52 using namespace android;
53 
54 namespace qhwc {
55 
56 #define MAX_SYSFS_FILE_PATH             255
57 
58 /* Max. resolution assignable to virtual display. */
59 #define SUPPORTED_VIRTUAL_AREA          (1920*1080)
60 
configure()61 int VirtualDisplay::configure() {
62     if(!openFrameBuffer())
63         return -1;
64 
65     if(ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo) < 0) {
66         ALOGD("%s: FBIOGET_VSCREENINFO failed with %s", __FUNCTION__,
67                 strerror(errno));
68         return -1;
69     }
70     setAttributes();
71     return 0;
72 }
73 
getAttributes(int & width,int & height)74 void VirtualDisplay::getAttributes(int& width, int& height) {
75     width = mVInfo.xres;
76     height = mVInfo.yres;
77 }
78 
teardown()79 int VirtualDisplay::teardown() {
80     closeFrameBuffer();
81     memset(&mVInfo, 0, sizeof(mVInfo));
82     // Reset the resolution when we close the fb for this device. We need
83     // this to distinguish between an ONLINE and RESUME event.
84     mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = 0;
85     mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = 0;
86     return 0;
87 }
88 
VirtualDisplay(hwc_context_t * ctx)89 VirtualDisplay::VirtualDisplay(hwc_context_t* ctx):mFd(-1),
90      mHwcContext(ctx)
91 {
92     memset(&mVInfo, 0, sizeof(mVInfo));
93 }
94 
~VirtualDisplay()95 VirtualDisplay::~VirtualDisplay()
96 {
97     closeFrameBuffer();
98 }
99 
100 /* Initializes the resolution attributes of the virtual display
101    that are reported to SurfaceFlinger.
102    Cases:
103        1. ONLINE event - initialize to frame buffer resolution
104        2. RESUME event - retain original resolution
105 */
initResolution(uint32_t & extW,uint32_t & extH)106 void VirtualDisplay::initResolution(uint32_t &extW, uint32_t &extH) {
107     // On ONLINE event, display resolution attributes are 0.
108     if(extW == 0 || extH == 0){
109         extW = mVInfo.xres;
110         extH = mVInfo.yres;
111     }
112 }
113 
114 /* Sets the virtual resolution to match that of the primary
115    display in the event that the virtual display currently
116    connected has a lower resolution. NB: we always report the
117    highest available resolution to SurfaceFlinger.
118 */
setToPrimary(uint32_t maxArea,uint32_t priW,uint32_t priH,uint32_t & extW,uint32_t & extH)119 void VirtualDisplay::setToPrimary(uint32_t maxArea,
120                                   uint32_t priW,
121                                   uint32_t priH,
122                                   uint32_t &extW,
123                                   uint32_t &extH) {
124     // for eg., primary in 1600p and WFD in 1080p
125     // we wont use downscale feature because MAX MDP
126     // writeback resolution supported is 1080p (tracked
127     // by SUPPORTED_VIRTUAL_AREA).
128     if((maxArea == (priW * priH))
129         && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
130         extW = priW;
131         extH = priH;
132         // If WFD is in landscape, assign the higher dimension
133         // to WFD's xres.
134         if(priH > priW) {
135             extW = priH;
136             extH = priW;
137         }
138     }
139 }
140 
141 /* Set External Display MDP Downscale mode indicator. Only set to
142    TRUE for the following scenarios:
143    1. Valid DRC scenarios i.e. when the original WFD resolution
144       is greater than the new/requested resolution in mVInfo.
145    2. WFD down scale path i.e. when WFD resolution is lower than
146       primary resolution.
147    Furthermore, downscale mode is only valid when downscaling from
148    SUPPORTED_VIRTUAL_AREA to a lower resolution.
149    (SUPPORTED_VIRTUAL_AREA represents the maximum resolution that
150    we can configure to the virtual display)
151 */
setDownScaleMode(uint32_t maxArea)152 void VirtualDisplay::setDownScaleMode(uint32_t maxArea) {
153     if((maxArea > (mVInfo.xres * mVInfo.yres))
154         && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
155         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
156     }else {
157         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
158     }
159 }
160 
setAttributes()161 void VirtualDisplay::setAttributes() {
162     if(mHwcContext) {
163         uint32_t &extW = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres;
164         uint32_t &extH = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres;
165         uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
166         uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
167 
168         initResolution(extW, extH);
169 
170         // Dynamic Resolution Change depends on MDP downscaling.
171         // MDP downscale property will be ignored to exercise DRC use case.
172         // If DRC is in progress, ext WxH will have non-zero values.
173         bool isDRC = (extW > 0) && (extH > 0);
174 
175         if(!qdutils::MDPVersion::getInstance().is8x26()
176                 && (mHwcContext->mMDPDownscaleEnabled || isDRC)) {
177 
178             // maxArea represents the maximum resolution between
179             // primary and virtual display.
180             uint32_t maxArea = max((extW * extH), (priW * priH));
181 
182             setToPrimary(maxArea, priW, priH, extW, extH);
183 
184             setDownScaleMode(maxArea);
185         }
186         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
187                 1000000000l /60;
188         ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,
189                  mVInfo.xres, mVInfo.yres);
190     }
191 }
192 
openFrameBuffer()193 bool VirtualDisplay::openFrameBuffer()
194 {
195     if (mFd == -1) {
196         int fbNum = overlay::Overlay::getInstance()->
197                                    getFbForDpy(HWC_DISPLAY_VIRTUAL);
198 
199         char strDevPath[MAX_SYSFS_FILE_PATH];
200         snprintf(strDevPath,sizeof(strDevPath), "/dev/graphics/fb%d", fbNum);
201 
202         mFd = open(strDevPath, O_RDWR);
203         if(mFd < 0) {
204             ALOGE("%s: Unable to open %s ", __FUNCTION__,strDevPath);
205             return -1;
206         }
207 
208         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
209     }
210     return 1;
211 }
212 
closeFrameBuffer()213 bool VirtualDisplay::closeFrameBuffer()
214 {
215     if(mFd >= 0) {
216         if(close(mFd) < 0 ) {
217             ALOGE("%s: Unable to close FD(%d)", __FUNCTION__, mFd);
218             return -1;
219         }
220         mFd = -1;
221         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
222     }
223     return 1;
224 }
225 };
226