1 /* 2 * Copyright (c) 2013-14, 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 CLIENTS; 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 <hwc_qclient.h> 31 #include <IQService.h> 32 #include <hwc_utils.h> 33 #include <mdp_version.h> 34 #include <hwc_mdpcomp.h> 35 36 #define QCLIENT_DEBUG 0 37 38 using namespace android; 39 using namespace qService; 40 using namespace qhwc; 41 42 namespace qClient { 43 44 // ---------------------------------------------------------------------------- 45 QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx), 46 mMPDeathNotifier(new MPDeathNotifier(ctx)) 47 { 48 ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked"); 49 } 50 51 QClient::~QClient() 52 { 53 ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked"); 54 } 55 56 static void securing(hwc_context_t *ctx, uint32_t startEnd) { 57 Locker::Autolock _sl(ctx->mDrawLock); 58 //The only way to make this class in this process subscribe to media 59 //player's death. 60 IMediaDeathNotifier::getMediaPlayerService(); 61 62 ctx->mSecuring = startEnd; 63 //We're done securing 64 if(startEnd == IQService::END) 65 ctx->mSecureMode = true; 66 if(ctx->proc) 67 ctx->proc->invalidate(ctx->proc); 68 } 69 70 static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) { 71 Locker::Autolock _sl(ctx->mDrawLock); 72 ctx->mSecuring = startEnd; 73 //We're done unsecuring 74 if(startEnd == IQService::END) 75 ctx->mSecureMode = false; 76 if(ctx->proc) 77 ctx->proc->invalidate(ctx->proc); 78 } 79 80 void QClient::MPDeathNotifier::died() { 81 Locker::Autolock _sl(mHwcContext->mDrawLock); 82 ALOGD_IF(QCLIENT_DEBUG, "Media Player died"); 83 mHwcContext->mSecuring = false; 84 mHwcContext->mSecureMode = false; 85 if(mHwcContext->proc) 86 mHwcContext->proc->invalidate(mHwcContext->proc); 87 } 88 89 static android::status_t screenRefresh(hwc_context_t *ctx) { 90 status_t result = NO_INIT; 91 if(ctx->proc) { 92 ctx->proc->invalidate(ctx->proc); 93 result = NO_ERROR; 94 } 95 return result; 96 } 97 98 static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) { 99 ctx->mExtOrientation = orientation; 100 } 101 102 static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) { 103 int connected; 104 connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0; 105 outParcel->writeInt32(connected); 106 } 107 108 static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel, 109 Parcel* outParcel) { 110 int dpy = inParcel->readInt32(); 111 outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period); 112 if (ctx->dpyAttr[dpy].customFBSize) { 113 outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new); 114 outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new); 115 } else { 116 outParcel->writeInt32(ctx->dpyAttr[dpy].xres); 117 outParcel->writeInt32(ctx->dpyAttr[dpy].yres); 118 } 119 outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi); 120 outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi); 121 //XXX: Need to check what to return for HDMI 122 outParcel->writeInt32(ctx->mMDP.panel); 123 } 124 static void setHSIC(const Parcel* inParcel) { 125 int dpy = inParcel->readInt32(); 126 ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy); 127 HSICData_t hsic_data; 128 hsic_data.hue = inParcel->readInt32(); 129 hsic_data.saturation = inParcel->readFloat(); 130 hsic_data.intensity = inParcel->readInt32(); 131 hsic_data.contrast = inParcel->readFloat(); 132 //XXX: Actually set the HSIC data through ABL lib 133 } 134 135 136 static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) { 137 ctx->mBufferMirrorMode = enable; 138 } 139 140 static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy, 141 Parcel* outParcel) { 142 // Get the info only if the dpy is valid 143 if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { 144 Locker::Autolock _sl(ctx->mDrawLock); 145 if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) { 146 // Return the destRect on external, if external orienation 147 // is enabled 148 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left); 149 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top); 150 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right); 151 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom); 152 } else { 153 outParcel->writeInt32(ctx->mViewFrame[dpy].left); 154 outParcel->writeInt32(ctx->mViewFrame[dpy].top); 155 outParcel->writeInt32(ctx->mViewFrame[dpy].right); 156 outParcel->writeInt32(ctx->mViewFrame[dpy].bottom); 157 } 158 return NO_ERROR; 159 } else { 160 ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); 161 return BAD_VALUE; 162 } 163 } 164 165 static void pauseWFD(hwc_context_t *ctx, uint32_t pause) { 166 /* TODO: Will remove pauseWFD once all the clients start using 167 * setWfdStatus to indicate the status of WFD display 168 */ 169 int dpy = HWC_DISPLAY_VIRTUAL; 170 if(pause) { 171 //WFD Pause 172 handle_pause(ctx, dpy); 173 } else { 174 //WFD Resume 175 handle_resume(ctx, dpy); 176 } 177 } 178 179 static void setWfdStatus(hwc_context_t *ctx, uint32_t wfdStatus) { 180 181 ALOGD_IF(HWC_WFDDISPSYNC_LOG, 182 "%s: Received a binder call that WFD state is %s", 183 __FUNCTION__,getExternalDisplayState(wfdStatus)); 184 int dpy = HWC_DISPLAY_VIRTUAL; 185 186 if(wfdStatus == EXTERNAL_OFFLINE) { 187 ctx->mWfdSyncLock.lock(); 188 ctx->mWfdSyncLock.signal(); 189 ctx->mWfdSyncLock.unlock(); 190 } else if(wfdStatus == EXTERNAL_PAUSE) { 191 handle_pause(ctx, dpy); 192 } else if(wfdStatus == EXTERNAL_RESUME) { 193 handle_resume(ctx, dpy); 194 } 195 } 196 197 198 static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) { 199 int dpy = inParcel->readInt32(); 200 if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { 201 Locker::Autolock _sl(ctx->mDrawLock); 202 ctx->mViewFrame[dpy].left = inParcel->readInt32(); 203 ctx->mViewFrame[dpy].top = inParcel->readInt32(); 204 ctx->mViewFrame[dpy].right = inParcel->readInt32(); 205 ctx->mViewFrame[dpy].bottom = inParcel->readInt32(); 206 ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]", 207 __FUNCTION__, dpy, 208 ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top, 209 ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom); 210 return NO_ERROR; 211 } else { 212 ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); 213 return BAD_VALUE; 214 } 215 } 216 217 static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) { 218 int debug_type = inParcel->readInt32(); 219 bool enable = !!inParcel->readInt32(); 220 ALOGD("%s: debug_type: %d enable:%d", 221 __FUNCTION__, debug_type, enable); 222 Locker::Autolock _sl(ctx->mDrawLock); 223 switch (debug_type) { 224 //break is ignored for DEBUG_ALL to toggle all of them at once 225 case IQService::DEBUG_ALL: 226 case IQService::DEBUG_MDPCOMP: 227 qhwc::MDPComp::dynamicDebug(enable); 228 if (debug_type != IQService::DEBUG_ALL) 229 break; 230 case IQService::DEBUG_VSYNC: 231 ctx->vstate.debug = enable; 232 if (debug_type != IQService::DEBUG_ALL) 233 break; 234 } 235 } 236 237 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel, 238 Parcel* outParcel) { 239 status_t ret = NO_ERROR; 240 241 switch(command) { 242 case IQService::SECURING: 243 securing(mHwcContext, inParcel->readInt32()); 244 break; 245 case IQService::UNSECURING: 246 unsecuring(mHwcContext, inParcel->readInt32()); 247 break; 248 case IQService::SCREEN_REFRESH: 249 return screenRefresh(mHwcContext); 250 break; 251 case IQService::EXTERNAL_ORIENTATION: 252 setExtOrientation(mHwcContext, inParcel->readInt32()); 253 break; 254 case IQService::BUFFER_MIRRORMODE: 255 setBufferMirrorMode(mHwcContext, inParcel->readInt32()); 256 break; 257 case IQService::GET_DISPLAY_VISIBLE_REGION: 258 ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(), 259 outParcel); 260 break; 261 case IQService::CHECK_EXTERNAL_STATUS: 262 isExternalConnected(mHwcContext, outParcel); 263 break; 264 case IQService::GET_DISPLAY_ATTRIBUTES: 265 getDisplayAttributes(mHwcContext, inParcel, outParcel); 266 break; 267 case IQService::SET_HSIC_DATA: 268 setHSIC(inParcel); 269 break; 270 case IQService::PAUSE_WFD: 271 pauseWFD(mHwcContext, inParcel->readInt32()); 272 break; 273 case IQService::SET_WFD_STATUS: 274 setWfdStatus(mHwcContext,inParcel->readInt32()); 275 break; 276 case IQService::SET_VIEW_FRAME: 277 setViewFrame(mHwcContext, inParcel); 278 break; 279 case IQService::DYNAMIC_DEBUG: 280 toggleDynamicDebug(mHwcContext, inParcel); 281 break; 282 default: 283 ret = NO_ERROR; 284 } 285 return ret; 286 } 287 288 } 289