1/* 2 * Copyright (c) 2013-15, 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#include <hwc_virtual.h> 36#include <overlay.h> 37#include <display_config.h> 38#include <hwc_qdcm.h> 39 40#define QCLIENT_DEBUG 0 41 42using namespace android; 43using namespace qService; 44using namespace qhwc; 45using namespace overlay; 46using namespace qdutils; 47using namespace qQdcm; 48 49namespace qClient { 50 51// ---------------------------------------------------------------------------- 52QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx), 53 mMPDeathNotifier(new MPDeathNotifier(ctx)) 54{ 55 ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked"); 56} 57 58QClient::~QClient() 59{ 60 ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked"); 61} 62 63static void securing(hwc_context_t *ctx, uint32_t startEnd) { 64 //The only way to make this class in this process subscribe to media 65 //player's death. 66 IMediaDeathNotifier::getMediaPlayerService(); 67 68 ctx->mDrawLock.lock(); 69 ctx->mSecuring = startEnd; 70 //We're done securing 71 if(startEnd == IQService::END) 72 ctx->mSecureMode = true; 73 ctx->mDrawLock.unlock(); 74 75 if(ctx->proc) 76 ctx->proc->invalidate(ctx->proc); 77} 78 79static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) { 80 ctx->mDrawLock.lock(); 81 ctx->mSecuring = startEnd; 82 //We're done unsecuring 83 if(startEnd == IQService::END) 84 ctx->mSecureMode = false; 85 ctx->mDrawLock.unlock(); 86 87 if(ctx->proc) 88 ctx->proc->invalidate(ctx->proc); 89} 90 91void QClient::MPDeathNotifier::died() { 92 mHwcContext->mDrawLock.lock(); 93 ALOGD_IF(QCLIENT_DEBUG, "Media Player died"); 94 mHwcContext->mSecuring = false; 95 mHwcContext->mSecureMode = false; 96 mHwcContext->mDrawLock.unlock(); 97 if(mHwcContext->proc) 98 mHwcContext->proc->invalidate(mHwcContext->proc); 99} 100 101static android::status_t screenRefresh(hwc_context_t *ctx) { 102 status_t result = NO_INIT; 103 if(ctx->proc) { 104 ctx->proc->invalidate(ctx->proc); 105 result = NO_ERROR; 106 } 107 return result; 108} 109 110static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) { 111 ctx->mExtOrientation = orientation; 112} 113 114static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) { 115 int connected; 116 connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0; 117 outParcel->writeInt32(connected); 118} 119 120static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel, 121 Parcel* outParcel) { 122 int dpy = inParcel->readInt32(); 123 outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period); 124 if (ctx->dpyAttr[dpy].customFBSize) { 125 outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new); 126 outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new); 127 } else { 128 outParcel->writeInt32(ctx->dpyAttr[dpy].xres); 129 outParcel->writeInt32(ctx->dpyAttr[dpy].yres); 130 } 131 outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi); 132 outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi); 133 //XXX: Need to check what to return for HDMI 134 outParcel->writeInt32(ctx->mMDP.panel); 135} 136static void setHSIC(const Parcel* inParcel) { 137 int dpy = inParcel->readInt32(); 138 ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy); 139 HSICData_t hsic_data; 140 hsic_data.hue = inParcel->readInt32(); 141 hsic_data.saturation = inParcel->readFloat(); 142 hsic_data.intensity = inParcel->readInt32(); 143 hsic_data.contrast = inParcel->readFloat(); 144 //XXX: Actually set the HSIC data through ABL lib 145} 146 147 148static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) { 149 ctx->mBufferMirrorMode = enable; 150} 151 152static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy, 153 Parcel* outParcel) { 154 // Get the info only if the dpy is valid 155 if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { 156 Locker::Autolock _sl(ctx->mDrawLock); 157 if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) { 158 // Return the destRect on external, if external orienation 159 // is enabled 160 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left); 161 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top); 162 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right); 163 outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom); 164 } else { 165 outParcel->writeInt32(ctx->mViewFrame[dpy].left); 166 outParcel->writeInt32(ctx->mViewFrame[dpy].top); 167 outParcel->writeInt32(ctx->mViewFrame[dpy].right); 168 outParcel->writeInt32(ctx->mViewFrame[dpy].bottom); 169 } 170 return NO_ERROR; 171 } else { 172 ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); 173 return BAD_VALUE; 174 } 175} 176 177// USed for setting the secondary(hdmi/wfd) status 178static void setSecondaryDisplayStatus(hwc_context_t *ctx, 179 const Parcel* inParcel) { 180 uint32_t dpy = inParcel->readInt32(); 181 uint32_t status = inParcel->readInt32(); 182 ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__, 183 dpy, getExternalDisplayState(status)); 184 185 if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { 186 if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) { 187 ctx->mWfdSyncLock.lock(); 188 ctx->mWfdSyncLock.signal(); 189 ctx->mWfdSyncLock.unlock(); 190 } else if(status == qdutils::EXTERNAL_PAUSE) { 191 handle_pause(ctx, dpy); 192 } else if(status == qdutils::EXTERNAL_RESUME) { 193 handle_resume(ctx, dpy); 194 } 195 } else { 196 ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy); 197 return; 198 } 199} 200 201 202static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) { 203 int dpy = inParcel->readInt32(); 204 if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { 205 Locker::Autolock _sl(ctx->mDrawLock); 206 ctx->mViewFrame[dpy].left = inParcel->readInt32(); 207 ctx->mViewFrame[dpy].top = inParcel->readInt32(); 208 ctx->mViewFrame[dpy].right = inParcel->readInt32(); 209 ctx->mViewFrame[dpy].bottom = inParcel->readInt32(); 210 ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]", 211 __FUNCTION__, dpy, 212 ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top, 213 ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom); 214 return NO_ERROR; 215 } else { 216 ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); 217 return BAD_VALUE; 218 } 219} 220 221static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) { 222 int debug_type = inParcel->readInt32(); 223 bool enable = !!inParcel->readInt32(); 224 ALOGD("%s: debug_type: %d enable:%d", 225 __FUNCTION__, debug_type, enable); 226 Locker::Autolock _sl(ctx->mDrawLock); 227 switch (debug_type) { 228 //break is ignored for DEBUG_ALL to toggle all of them at once 229 case IQService::DEBUG_ALL: 230 case IQService::DEBUG_MDPCOMP: 231 qhwc::MDPComp::dynamicDebug(enable); 232 if (debug_type != IQService::DEBUG_ALL) 233 break; 234 case IQService::DEBUG_VSYNC: 235 ctx->vstate.debug = enable; 236 if (debug_type != IQService::DEBUG_ALL) 237 break; 238 case IQService::DEBUG_VD: 239 HWCVirtualVDS::dynamicDebug(enable); 240 if (debug_type != IQService::DEBUG_ALL) 241 break; 242 case IQService::DEBUG_PIPE_LIFECYCLE: 243 Overlay::debugPipeLifecycle(enable); 244 if (debug_type != IQService::DEBUG_ALL) 245 break; 246 } 247} 248 249static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) { 250 uint32_t timeout = (uint32_t)inParcel->readInt32(); 251 ALOGD("%s :%u ms", __FUNCTION__, timeout); 252 Locker::Autolock _sl(ctx->mDrawLock); 253 MDPComp::setIdleTimeout(timeout); 254} 255 256static void configureDynRefreshRate(hwc_context_t* ctx, 257 const Parcel* inParcel) { 258 uint32_t op = (uint32_t)inParcel->readInt32(); 259 uint32_t refresh_rate = (uint32_t)inParcel->readInt32(); 260 MDPVersion& mdpHw = MDPVersion::getInstance(); 261 uint32_t dpy = HWC_DISPLAY_PRIMARY; 262 263 if(mdpHw.isDynFpsSupported()) { 264 Locker::Autolock _sl(ctx->mDrawLock); 265 266 switch (op) { 267 case DISABLE_METADATA_DYN_REFRESH_RATE: 268 ctx->mUseMetaDataRefreshRate = false; 269 setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate); 270 break; 271 case ENABLE_METADATA_DYN_REFRESH_RATE: 272 ctx->mUseMetaDataRefreshRate = true; 273 setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate); 274 break; 275 case SET_BINDER_DYN_REFRESH_RATE: 276 if(ctx->mUseMetaDataRefreshRate) 277 ALOGW("%s: Ignoring binder request to change refresh-rate", 278 __FUNCTION__); 279 else { 280 uint32_t rate = roundOff(refresh_rate); 281 if((rate >= mdpHw.getMinFpsSupported() && 282 rate <= mdpHw.getMaxFpsSupported())) { 283 setRefreshRate(ctx, dpy, rate); 284 } else { 285 ALOGE("%s: Requested refresh-rate should be between \ 286 (%d) and (%d). Given (%d)", __FUNCTION__, 287 mdpHw.getMinFpsSupported(), 288 mdpHw.getMaxFpsSupported(), rate); 289 } 290 } 291 break; 292 default: 293 ALOGE("%s: Invalid op %d",__FUNCTION__,op); 294 } 295 } 296} 297 298static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) { 299 ALOGD("%s: state: %d", __FUNCTION__, state); 300 switch(state) { 301 case IQService::PREF_PARTIAL_UPDATE: 302 if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0) 303 return NO_INIT; 304 return NO_ERROR; 305 case IQService::PREF_POST_PROCESSING: 306 if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0) 307 return NO_INIT; 308 qhwc::MDPComp::enablePartialUpdate(false); 309 return NO_ERROR; 310 case IQService::ENABLE_PARTIAL_UPDATE: 311 qhwc::MDPComp::enablePartialUpdate(true); 312 return NO_ERROR; 313 default: 314 ALOGE("%s: Invalid state", __FUNCTION__); 315 return NO_ERROR; 316 }; 317} 318 319static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) { 320 ALOGD("%s: toggle update: %d", __FUNCTION__, on); 321 if (on == 0) { 322 ctx->mDrawLock.lock(); 323 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true; 324 ctx->mOverlay->configBegin(); 325 ctx->mOverlay->configDone(); 326 ctx->mRotMgr->clear(); 327 if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) { 328 ALOGE("%s: Display commit failed", __FUNCTION__); 329 } 330 ctx->mDrawLock.unlock(); 331 } else { 332 ctx->mDrawLock.lock(); 333 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false; 334 ctx->mDrawLock.unlock(); 335 ctx->proc->invalidate(ctx->proc); 336 } 337} 338 339status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel, 340 Parcel* outParcel) { 341 status_t ret = NO_ERROR; 342 343 switch(command) { 344 case IQService::SECURING: 345 securing(mHwcContext, inParcel->readInt32()); 346 break; 347 case IQService::UNSECURING: 348 unsecuring(mHwcContext, inParcel->readInt32()); 349 break; 350 case IQService::SCREEN_REFRESH: 351 return screenRefresh(mHwcContext); 352 break; 353 case IQService::EXTERNAL_ORIENTATION: 354 setExtOrientation(mHwcContext, inParcel->readInt32()); 355 break; 356 case IQService::BUFFER_MIRRORMODE: 357 setBufferMirrorMode(mHwcContext, inParcel->readInt32()); 358 break; 359 case IQService::GET_DISPLAY_VISIBLE_REGION: 360 ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(), 361 outParcel); 362 break; 363 case IQService::CHECK_EXTERNAL_STATUS: 364 isExternalConnected(mHwcContext, outParcel); 365 break; 366 case IQService::GET_DISPLAY_ATTRIBUTES: 367 getDisplayAttributes(mHwcContext, inParcel, outParcel); 368 break; 369 case IQService::SET_HSIC_DATA: 370 setHSIC(inParcel); 371 break; 372 case IQService::SET_SECONDARY_DISPLAY_STATUS: 373 setSecondaryDisplayStatus(mHwcContext, inParcel); 374 break; 375 case IQService::SET_VIEW_FRAME: 376 setViewFrame(mHwcContext, inParcel); 377 break; 378 case IQService::DYNAMIC_DEBUG: 379 toggleDynamicDebug(mHwcContext, inParcel); 380 break; 381 case IQService::SET_IDLE_TIMEOUT: 382 setIdleTimeout(mHwcContext, inParcel); 383 break; 384 case IQService::SET_PARTIAL_UPDATE: 385 ret = setPartialUpdateState(mHwcContext, inParcel->readInt32()); 386 break; 387 case IQService::CONFIGURE_DYN_REFRESH_RATE: 388 configureDynRefreshRate(mHwcContext, inParcel); 389 case IQService::QDCM_SVC_CMDS: 390 qdcmCmdsHandler(mHwcContext, inParcel, outParcel); 391 break; 392 case IQService::TOGGLE_SCREEN_UPDATE: 393 toggleScreenUpdate(mHwcContext, inParcel->readInt32()); 394 break; 395 default: 396 ret = NO_ERROR; 397 } 398 return ret; 399} 400 401} 402