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