Iliyan Malchev | 202a77d | 2012-06-11 14:41:12 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2008 The Android Open Source Project |
| 3 | * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #include "overlayLibUI.h" |
| 19 | #include "gralloc_priv.h" |
| 20 | #define LOG_TAG "OverlayUI" |
| 21 | |
| 22 | using android::sp; |
| 23 | using gralloc::IMemAlloc; |
| 24 | using gralloc::alloc_data; |
| 25 | |
| 26 | namespace { |
| 27 | /* helper functions */ |
| 28 | void swapOVRotWidthHeight(msm_rotator_img_info& rotInfo, |
| 29 | mdp_overlay& ovInfo) { |
| 30 | int srcWidth = ovInfo.src.width; |
| 31 | ovInfo.src.width = ovInfo.src.height; |
| 32 | ovInfo.src.height = srcWidth; |
| 33 | |
| 34 | int srcRectWidth = ovInfo.src_rect.w; |
| 35 | ovInfo.src_rect.w = ovInfo.src_rect.h; |
| 36 | ovInfo.src_rect.h = srcRectWidth; |
| 37 | |
| 38 | int dstWidth = rotInfo.dst.width; |
| 39 | rotInfo.dst.width = rotInfo.dst.height; |
| 40 | rotInfo.dst.height = dstWidth; |
| 41 | } |
| 42 | |
| 43 | bool isRGBType(int format) { |
| 44 | bool ret = false; |
| 45 | switch(format) { |
| 46 | case MDP_RGBA_8888: |
| 47 | case MDP_BGRA_8888: |
| 48 | case MDP_RGBX_8888: |
| 49 | case MDP_RGB_565: |
| 50 | ret = true; |
| 51 | break; |
| 52 | default: |
| 53 | ret = false; |
| 54 | break; |
| 55 | } |
| 56 | return ret; |
| 57 | } |
| 58 | |
| 59 | int getRGBBpp(int format) { |
| 60 | int ret = -1; |
| 61 | switch(format) { |
| 62 | case MDP_RGBA_8888: |
| 63 | case MDP_BGRA_8888: |
| 64 | case MDP_RGBX_8888: |
| 65 | ret = 4; |
| 66 | break; |
| 67 | case MDP_RGB_565: |
| 68 | ret = 2; |
| 69 | break; |
| 70 | default: |
| 71 | ret = -1; |
| 72 | break; |
| 73 | } |
| 74 | |
| 75 | return ret; |
| 76 | } |
| 77 | |
| 78 | bool turnOFFVSync() { |
| 79 | static int swapIntervalPropVal = -1; |
| 80 | if (swapIntervalPropVal == -1) { |
| 81 | char pval[PROPERTY_VALUE_MAX]; |
| 82 | property_get("debug.gr.swapinterval", pval, "1"); |
| 83 | swapIntervalPropVal = atoi(pval); |
| 84 | } |
| 85 | return (swapIntervalPropVal == 0); |
| 86 | } |
| 87 | |
| 88 | }; |
| 89 | |
| 90 | namespace overlay { |
| 91 | |
| 92 | status_t Display::openDisplay(int fbnum) { |
| 93 | if (mFD != NO_INIT) |
| 94 | return NO_ERROR; |
| 95 | |
| 96 | status_t ret = NO_INIT; |
| 97 | char dev_name[64]; |
| 98 | snprintf(dev_name, 64, FB_DEVICE_TEMPLATE, fbnum); |
| 99 | |
| 100 | mFD = open(dev_name, O_RDWR, 0); |
| 101 | if (mFD < 0) { |
| 102 | LOGE("Failed to open FB %d", fbnum); |
| 103 | return ret; |
| 104 | } |
| 105 | |
| 106 | fb_var_screeninfo vinfo; |
| 107 | if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo)) { |
| 108 | LOGE("FBIOGET_VSCREENINFO on failed on FB %d", fbnum); |
| 109 | close(mFD); |
| 110 | mFD = NO_INIT; |
| 111 | return ret; |
| 112 | } |
| 113 | |
| 114 | mFBWidth = vinfo.xres; |
| 115 | mFBHeight = vinfo.yres; |
| 116 | mFBBpp = vinfo.bits_per_pixel; |
| 117 | ret = NO_ERROR; |
| 118 | |
| 119 | return ret; |
| 120 | } |
| 121 | |
| 122 | void Display::closeDisplay() { |
| 123 | close(mFD); |
| 124 | mFD = NO_INIT; |
| 125 | } |
| 126 | |
| 127 | Rotator::Rotator() : mFD(NO_INIT), mSessionID(NO_INIT), mPmemFD(NO_INIT) |
| 128 | { |
| 129 | mAlloc = gralloc::IAllocController::getInstance(false); |
| 130 | } |
| 131 | |
| 132 | Rotator::~Rotator() |
| 133 | { |
| 134 | closeRotSession(); |
| 135 | } |
| 136 | |
| 137 | status_t Rotator::startRotSession(msm_rotator_img_info& rotInfo, |
| 138 | int size, int numBuffers) { |
| 139 | status_t ret = NO_ERROR; |
| 140 | if (mSessionID == NO_INIT && mFD == NO_INIT) { |
| 141 | mNumBuffers = numBuffers; |
| 142 | mFD = open("/dev/msm_rotator", O_RDWR, 0); |
| 143 | if (mFD < 0) { |
| 144 | LOGE("Couldnt open rotator device"); |
| 145 | return NO_INIT; |
| 146 | } |
| 147 | |
| 148 | if (ioctl(mFD, MSM_ROTATOR_IOCTL_START, &rotInfo)) { |
| 149 | close(mFD); |
| 150 | mFD = NO_INIT; |
| 151 | return NO_INIT; |
| 152 | } |
| 153 | |
| 154 | mSessionID = rotInfo.session_id; |
| 155 | alloc_data data; |
| 156 | data.base = 0; |
| 157 | data.fd = -1; |
| 158 | data.offset = 0; |
| 159 | data.size = mSize * mNumBuffers; |
| 160 | data.align = getpagesize(); |
| 161 | data.uncached = true; |
| 162 | |
| 163 | int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP | |
| 164 | GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP | |
| 165 | GRALLOC_USAGE_PRIVATE_ADSP_HEAP | |
| 166 | GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | |
| 167 | GRALLOC_USAGE_PRIVATE_SMI_HEAP | |
| 168 | GRALLOC_USAGE_PRIVATE_DO_NOT_MAP; |
| 169 | |
| 170 | int err = mAlloc->allocate(data, allocFlags, 0); |
| 171 | |
| 172 | if(err) { |
| 173 | LOGE("%s: Can't allocate rotator memory", __func__); |
| 174 | closeRotSession(); |
| 175 | return NO_INIT; |
| 176 | } |
| 177 | mPmemFD = data.fd; |
| 178 | mPmemAddr = data.base; |
| 179 | mBufferType = data.allocType; |
| 180 | |
| 181 | mCurrentItem = 0; |
| 182 | for (int i = 0; i < mNumBuffers; i++) |
| 183 | mRotOffset[i] = i * mSize; |
| 184 | ret = NO_ERROR; |
| 185 | } |
| 186 | return ret; |
| 187 | } |
| 188 | |
| 189 | status_t Rotator::closeRotSession() { |
| 190 | if (mSessionID != NO_INIT && mFD != NO_INIT) { |
| 191 | ioctl(mFD, MSM_ROTATOR_IOCTL_FINISH, &mSessionID); |
| 192 | close(mFD); |
| 193 | if (NO_INIT != mPmemFD) { |
| 194 | sp<IMemAlloc> memalloc = mAlloc->getAllocator(mBufferType); |
| 195 | memalloc->free_buffer(mPmemAddr, mSize * mNumBuffers, 0, mPmemFD); |
| 196 | close(mPmemFD); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | mFD = NO_INIT; |
| 201 | mSessionID = NO_INIT; |
| 202 | mPmemFD = NO_INIT; |
| 203 | mPmemAddr = MAP_FAILED; |
| 204 | |
| 205 | return NO_ERROR; |
| 206 | } |
| 207 | |
| 208 | status_t Rotator::rotateBuffer(msm_rotator_data_info& rotData) { |
| 209 | status_t ret = NO_INIT; |
| 210 | if (mSessionID != NO_INIT) { |
| 211 | rotData.dst.memory_id = mPmemFD; |
| 212 | rotData.dst.offset = mRotOffset[mCurrentItem]; |
| 213 | rotData.session_id = mSessionID; |
| 214 | mCurrentItem = (mCurrentItem + 1) % mNumBuffers; |
| 215 | if (ioctl(mFD, MSM_ROTATOR_IOCTL_ROTATE, &rotData)) { |
| 216 | LOGE("Rotator failed to rotate"); |
| 217 | return BAD_VALUE; |
| 218 | } |
| 219 | return NO_ERROR; |
| 220 | } |
| 221 | |
| 222 | return ret; |
| 223 | } |
| 224 | |
| 225 | //===================== OverlayUI =================// |
| 226 | |
| 227 | OverlayUI::OverlayUI() : mChannelState(CLOSED), mOrientation(NO_INIT), |
| 228 | mFBNum(NO_INIT), mZorder(NO_INIT), mWaitForVsync(false), mIsFg(false), |
| 229 | mSessionID(NO_INIT), mParamsChanged(false) { |
| 230 | memset(&mOvInfo, 0, sizeof(mOvInfo)); |
| 231 | memset(&mRotInfo, 0, sizeof(mRotInfo)); |
| 232 | } |
| 233 | |
| 234 | OverlayUI::~OverlayUI() { |
| 235 | closeChannel(); |
| 236 | } |
| 237 | |
| 238 | void OverlayUI::setSource(const overlay_buffer_info& info, int orientation) { |
| 239 | status_t ret = NO_INIT; |
| 240 | int format3D = FORMAT_3D(info.format); |
| 241 | int colorFormat = COLOR_FORMAT(info.format); |
| 242 | int format = get_mdp_format(colorFormat); |
| 243 | |
| 244 | if (format3D || !isRGBType(format)) { |
| 245 | LOGE("%s: Unsupported format", __func__); |
| 246 | return; |
| 247 | } |
| 248 | |
| 249 | mParamsChanged |= (mSource.width ^ info.width) || |
| 250 | (mSource.height ^ info.height) || |
| 251 | (mSource.format ^ format) || |
| 252 | (mSource.size ^ info.size) || |
| 253 | (mOrientation ^ orientation); |
| 254 | |
| 255 | mSource.width = info.width; |
| 256 | mSource.height = info.height; |
| 257 | mSource.format = format; |
| 258 | mSource.size = info.size; |
| 259 | mOrientation = orientation; |
| 260 | setupOvRotInfo(); |
| 261 | } |
| 262 | |
| 263 | void OverlayUI::setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int |
| 264 | zorder, bool isVGPipe) { |
| 265 | int flags = 0; |
| 266 | |
| 267 | if(false == waitForVsync) |
| 268 | flags |= MDP_OV_PLAY_NOWAIT; |
| 269 | else |
| 270 | flags &= ~MDP_OV_PLAY_NOWAIT; |
| 271 | |
| 272 | if(isVGPipe) |
| 273 | flags |= MDP_OV_PIPE_SHARE; |
| 274 | else |
| 275 | flags &= ~MDP_OV_PIPE_SHARE; |
| 276 | |
| 277 | if (turnOFFVSync()) |
| 278 | flags |= MDP_OV_PLAY_NOWAIT; |
| 279 | |
| 280 | mParamsChanged |= (mFBNum ^ fbNum) || |
| 281 | (mOvInfo.is_fg ^ isFg) || |
| 282 | (mOvInfo.flags ^ flags) || |
| 283 | (mOvInfo.z_order ^ zorder); |
| 284 | |
| 285 | mFBNum = fbNum; |
| 286 | mOvInfo.is_fg = isFg; |
| 287 | mOvInfo.flags = flags; |
| 288 | mOvInfo.z_order = zorder; |
| 289 | |
| 290 | mobjDisplay.openDisplay(mFBNum); |
| 291 | } |
| 292 | |
| 293 | void OverlayUI::setPosition(int x, int y, int w, int h) { |
| 294 | mParamsChanged |= (mOvInfo.dst_rect.x ^ x) || |
| 295 | (mOvInfo.dst_rect.y ^ y) || |
| 296 | (mOvInfo.dst_rect.w ^ w) || |
| 297 | (mOvInfo.dst_rect.h ^ h); |
| 298 | |
| 299 | mOvInfo.dst_rect.x = x; |
| 300 | mOvInfo.dst_rect.y = y; |
| 301 | mOvInfo.dst_rect.w = w; |
| 302 | mOvInfo.dst_rect.h = h; |
| 303 | } |
| 304 | |
| 305 | void OverlayUI::setCrop(int x, int y, int w, int h) { |
| 306 | mParamsChanged |= (mOvInfo.src_rect.x ^ x) || |
| 307 | (mOvInfo.src_rect.y ^ y) || |
| 308 | (mOvInfo.src_rect.w ^ w) || |
| 309 | (mOvInfo.src_rect.h ^ h); |
| 310 | |
| 311 | mOvInfo.src_rect.x = x; |
| 312 | mOvInfo.src_rect.y = y; |
| 313 | mOvInfo.src_rect.w = w; |
| 314 | mOvInfo.src_rect.h = h; |
| 315 | } |
| 316 | |
| 317 | void OverlayUI::setupOvRotInfo() { |
| 318 | int w = mSource.width; |
| 319 | int h = mSource.height; |
| 320 | int format = mSource.format; |
| 321 | int srcw = (w + 31) & ~31; |
| 322 | int srch = (h + 31) & ~31; |
| 323 | mOvInfo.src.width = srcw; |
| 324 | mOvInfo.src.height = srch; |
| 325 | mOvInfo.src.format = format; |
| 326 | mOvInfo.src_rect.w = w; |
| 327 | mOvInfo.src_rect.h = h; |
| 328 | mOvInfo.alpha = 0xff; |
| 329 | mOvInfo.transp_mask = 0xffffffff; |
| 330 | mRotInfo.src.format = format; |
| 331 | mRotInfo.dst.format = format; |
| 332 | mRotInfo.src.width = srcw; |
| 333 | mRotInfo.src.height = srch; |
| 334 | mRotInfo.src_rect.w = srcw; |
| 335 | mRotInfo.src_rect.h = srch; |
| 336 | mRotInfo.dst.width = srcw; |
| 337 | mRotInfo.dst.height = srch; |
| 338 | |
| 339 | int rot = mOrientation; |
| 340 | switch(rot) { |
| 341 | case 0: |
| 342 | case HAL_TRANSFORM_FLIP_H: |
| 343 | case HAL_TRANSFORM_FLIP_V: |
| 344 | rot = 0; |
| 345 | break; |
| 346 | case HAL_TRANSFORM_ROT_90: |
| 347 | case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): |
| 348 | case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): { |
| 349 | int tmp = mOvInfo.src_rect.x; |
| 350 | mOvInfo.src_rect.x = mOvInfo.src.height - |
| 351 | (mOvInfo.src_rect.y + mOvInfo.src_rect.h); |
| 352 | mOvInfo.src_rect.y = tmp; |
| 353 | swapOVRotWidthHeight(mRotInfo, mOvInfo); |
| 354 | rot = HAL_TRANSFORM_ROT_90; |
| 355 | break; |
| 356 | } |
| 357 | case HAL_TRANSFORM_ROT_180: |
| 358 | break; |
| 359 | case HAL_TRANSFORM_ROT_270: { |
| 360 | int tmp = mOvInfo.src_rect.y; |
| 361 | mOvInfo.src_rect.y = mOvInfo.src.width - |
| 362 | (mOvInfo.src_rect.x + mOvInfo.src_rect.w); |
| 363 | mOvInfo.src_rect.x = tmp; |
| 364 | swapOVRotWidthHeight(mRotInfo, mOvInfo); |
| 365 | break; |
| 366 | } |
| 367 | default: |
| 368 | break; |
| 369 | } |
| 370 | int mdp_rotation = overlay::get_mdp_orientation(rot); |
| 371 | if (mdp_rotation < 0) |
| 372 | mdp_rotation = 0; |
| 373 | mOvInfo.user_data[0] = mdp_rotation; |
| 374 | mRotInfo.rotations = mOvInfo.user_data[0]; |
| 375 | if (mdp_rotation) |
| 376 | mRotInfo.enable = 1; |
| 377 | } |
| 378 | |
| 379 | status_t OverlayUI::commit() { |
| 380 | status_t ret = BAD_VALUE; |
| 381 | if(mChannelState != UP) |
| 382 | mOvInfo.id = MSMFB_NEW_REQUEST; |
| 383 | ret = startOVSession(); |
| 384 | if (ret == NO_ERROR && mOrientation) { |
| 385 | ret = mobjRotator.startRotSession(mRotInfo, mSource.size); |
| 386 | } |
| 387 | if (ret == NO_ERROR) { |
| 388 | mChannelState = UP; |
| 389 | } else { |
| 390 | LOGE("start channel failed."); |
| 391 | } |
| 392 | return ret; |
| 393 | } |
| 394 | |
| 395 | status_t OverlayUI::closeChannel() { |
| 396 | if( mChannelState != UP ) { |
| 397 | return NO_ERROR; |
| 398 | } |
| 399 | if(NO_ERROR != closeOVSession()) { |
| 400 | LOGE("%s: closeOVSession() failed.", __FUNCTION__); |
| 401 | return BAD_VALUE; |
| 402 | } |
| 403 | if(NO_ERROR != mobjRotator.closeRotSession()) { |
| 404 | LOGE("%s: closeRotSession() failed.", __FUNCTION__); |
| 405 | return BAD_VALUE; |
| 406 | } |
| 407 | mChannelState = CLOSED; |
| 408 | mParamsChanged = false; |
| 409 | memset(&mOvInfo, 0, sizeof(mOvInfo)); |
| 410 | memset(&mRotInfo, 0, sizeof(mRotInfo)); |
| 411 | return NO_ERROR; |
| 412 | } |
| 413 | |
| 414 | status_t OverlayUI::startOVSession() { |
| 415 | status_t ret = NO_INIT; |
| 416 | ret = mobjDisplay.openDisplay(mFBNum); |
| 417 | |
| 418 | if (ret != NO_ERROR) |
| 419 | return ret; |
| 420 | |
| 421 | if(mParamsChanged) { |
| 422 | mParamsChanged = false; |
| 423 | mdp_overlay ovInfo = mOvInfo; |
| 424 | if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) { |
| 425 | LOGE("Overlay set failed.."); |
| 426 | ret = BAD_VALUE; |
| 427 | } else { |
| 428 | mSessionID = ovInfo.id; |
| 429 | mOvInfo = ovInfo; |
| 430 | ret = NO_ERROR; |
| 431 | } |
| 432 | } |
| 433 | return ret; |
| 434 | } |
| 435 | |
| 436 | status_t OverlayUI::closeOVSession() { |
| 437 | status_t ret = NO_ERROR; |
| 438 | int err = 0; |
| 439 | if(err = ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_UNSET, &mSessionID)) { |
| 440 | LOGE("%s: MSMFB_OVERLAY_UNSET failed. (%d)", __FUNCTION__, err); |
| 441 | ret = BAD_VALUE; |
| 442 | } else { |
| 443 | mobjDisplay.closeDisplay(); |
| 444 | mSessionID = NO_INIT; |
| 445 | } |
| 446 | return ret; |
| 447 | } |
| 448 | |
| 449 | status_t OverlayUI::queueBuffer(buffer_handle_t buffer) { |
| 450 | status_t ret = NO_INIT; |
| 451 | |
| 452 | if (mChannelState != UP) |
| 453 | return ret; |
| 454 | |
| 455 | msmfb_overlay_data ovData; |
| 456 | memset(&ovData, 0, sizeof(ovData)); |
| 457 | |
| 458 | private_handle_t const* hnd = reinterpret_cast |
| 459 | <private_handle_t const*>(buffer); |
| 460 | ovData.data.memory_id = hnd->fd; |
| 461 | ovData.data.offset = hnd->offset; |
| 462 | if (mOrientation) { |
| 463 | msm_rotator_data_info rotData; |
| 464 | memset(&rotData, 0, sizeof(rotData)); |
| 465 | rotData.src.memory_id = hnd->fd; |
| 466 | rotData.src.offset = hnd->offset; |
| 467 | if (mobjRotator.rotateBuffer(rotData) != NO_ERROR) { |
| 468 | LOGE("Rotator failed.. "); |
| 469 | return BAD_VALUE; |
| 470 | } |
| 471 | ovData.data.memory_id = rotData.dst.memory_id; |
| 472 | ovData.data.offset = rotData.dst.offset; |
| 473 | } |
| 474 | ovData.id = mSessionID; |
| 475 | if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_PLAY, &ovData)) { |
| 476 | LOGE("Queuebuffer failed "); |
| 477 | return BAD_VALUE; |
| 478 | } |
| 479 | return NO_ERROR; |
| 480 | } |
| 481 | |
| 482 | }; |