1/* 2// Copyright (c) 2014 Intel Corporation 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15*/ 16 17#include <math.h> 18#include <common/utils/HwcTrace.h> 19#include <common/base/Drm.h> 20#include <Hwcomposer.h> 21#include <PhysicalDevice.h> 22#include <ips/common/OverlayPlaneBase.h> 23#include <ips/common/TTMBufferMapper.h> 24#include <ips/common/GrallocSubBuffer.h> 25#include <DisplayQuery.h> 26#include <khronos/openmax/OMX_IntelVideoExt.h> 27#include <hal_public.h> 28 29namespace android { 30namespace intel { 31 32OverlayPlaneBase::OverlayPlaneBase(int index, int disp) 33 : DisplayPlane(index, PLANE_OVERLAY, disp), 34 mTTMBuffers(), 35 mActiveTTMBuffers(), 36 mCurrent(0), 37 mWsbm(0), 38 mPipeConfig(0), 39 mBobDeinterlace(0) 40{ 41 CTRACE(); 42 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 43 mBackBuffer[i] = 0; 44 } 45} 46 47OverlayPlaneBase::~OverlayPlaneBase() 48{ 49 CTRACE(); 50} 51 52bool OverlayPlaneBase::initialize(uint32_t bufferCount) 53{ 54 Drm *drm = Hwcomposer::getInstance().getDrm(); 55 CTRACE(); 56 57 // NOTE: use overlay's data buffer count for the overlay plane 58 if (bufferCount < OVERLAY_DATA_BUFFER_COUNT) { 59 ILOGTRACE("override overlay buffer count from %d to %d", 60 bufferCount, OVERLAY_DATA_BUFFER_COUNT); 61 bufferCount = OVERLAY_DATA_BUFFER_COUNT; 62 } 63 if (!DisplayPlane::initialize(bufferCount)) { 64 DEINIT_AND_RETURN_FALSE("failed to initialize display plane"); 65 } 66 67 mTTMBuffers.setCapacity(bufferCount); 68 mActiveTTMBuffers.setCapacity(MIN_DATA_BUFFER_COUNT); 69 70 // init wsbm 71 mWsbm = new Wsbm(drm->getDrmFd()); 72 if (!mWsbm || !mWsbm->initialize()) { 73 DEINIT_AND_RETURN_FALSE("failed to create wsbm"); 74 } 75 76 // create overlay back buffer 77 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 78 mBackBuffer[i] = createBackBuffer(); 79 if (!mBackBuffer[i]) { 80 DEINIT_AND_RETURN_FALSE("failed to create overlay back buffer"); 81 } 82 // reset back buffer 83 resetBackBuffer(i); 84 } 85 86 // disable overlay when created 87 flush(PLANE_DISABLE); 88 89 return true; 90} 91 92bool OverlayPlaneBase::isDisabled() 93{ 94 RETURN_FALSE_IF_NOT_INIT(); 95 96 struct drm_psb_register_rw_arg arg; 97 memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg)); 98 99 arg.get_plane_state_mask = 1; 100 arg.plane.type = DC_OVERLAY_PLANE; 101 arg.plane.index = mIndex; 102 // pass the pipe index to check its enabled status 103 // now we can pass the device id directly since 104 // their values are just equal 105 arg.plane.ctx = mDevice; // not used in kernel 106 107 Drm *drm = Hwcomposer::getInstance().getDrm(); 108 bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg)); 109 if (ret == false) { 110 WLOGTRACE("overlay plane query failed with error code %d", ret); 111 return false; 112 } 113 114 DLOGTRACE("overlay %d status %s on device %d, current device %d", 115 mIndex, arg.plane.ctx ? "DISABLED" : "ENABLED", mDevice, mDevice); 116 117 return arg.plane.ctx == PSB_DC_PLANE_DISABLED; 118} 119 120void OverlayPlaneBase::deinitialize() 121{ 122 if (mTTMBuffers.size()) { 123 invalidateBufferCache(); 124 } 125 126 if (mActiveTTMBuffers.size() > 0) { 127 invalidateActiveTTMBuffers(); 128 } 129 130 // delete back buffer 131 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 132 if (mBackBuffer[i]) { 133 deleteBackBuffer(i); 134 mBackBuffer[i] = NULL; 135 } 136 } 137 DEINIT_AND_DELETE_OBJ(mWsbm); 138 139 DisplayPlane::deinitialize(); 140} 141 142void OverlayPlaneBase::invalidateBufferCache() 143{ 144 // clear plane buffer cache 145 DisplayPlane::invalidateBufferCache(); 146 invalidateTTMBuffers(); 147} 148 149bool OverlayPlaneBase::assignToDevice(int disp) 150{ 151 uint32_t pipeConfig = 0; 152 153 RETURN_FALSE_IF_NOT_INIT(); 154 VLOGTRACE("overlay %d assigned to disp %d", mIndex, disp); 155 156 switch (disp) { 157 case IDisplayDevice::DEVICE_EXTERNAL: 158 pipeConfig = (0x2 << 6); 159 break; 160 case IDisplayDevice::DEVICE_PRIMARY: 161 default: 162 pipeConfig = 0; 163 break; 164 } 165 166 // if pipe switching happened, then disable overlay first 167 if (mPipeConfig != pipeConfig) { 168 DLOGTRACE("overlay %d switched from %d to %d", mIndex, mDevice, disp); 169 disable(); 170 } 171 172 mPipeConfig = pipeConfig; 173 DisplayPlane::assignToDevice(disp); 174 175 enable(); 176 177 return true; 178} 179 180void OverlayPlaneBase::setZOrderConfig(ZOrderConfig& zorderConfig, 181 void * /*nativeConfig*/) 182{ 183 CTRACE(); 184 185 // setup overlay z order 186 int ovaZOrder = -1; 187 int ovcZOrder = -1; 188 for (size_t i = 0; i < zorderConfig.size(); i++) { 189 DisplayPlane *plane = zorderConfig[i]->plane; 190 if (plane->getType() == DisplayPlane::PLANE_OVERLAY) { 191 if (plane->getIndex() == 0) { 192 ovaZOrder = i; 193 } else if (plane->getIndex() == 1) { 194 ovcZOrder = i; 195 } 196 } 197 } 198 199 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 200 OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; 201 if (!backBuffer) 202 return; 203 204 // force overlay c above overlay a 205 if ((ovaZOrder >= 0) && (ovaZOrder < ovcZOrder)) { 206 backBuffer->OCONFIG |= (1 << 15); 207 } else { 208 backBuffer->OCONFIG &= ~(1 << 15); 209 } 210 } 211} 212 213bool OverlayPlaneBase::reset() 214{ 215 RETURN_FALSE_IF_NOT_INIT(); 216 217 DisplayPlane::reset(); 218 219 // invalidate active TTM buffers 220 if (mActiveTTMBuffers.size() > 0) { 221 invalidateActiveTTMBuffers(); 222 } 223 224 // reset back buffers 225 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 226 resetBackBuffer(i); 227 } 228 return true; 229} 230 231bool OverlayPlaneBase::enable() 232{ 233 RETURN_FALSE_IF_NOT_INIT(); 234 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 235 OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; 236 if (!backBuffer) 237 return false; 238 239 if (backBuffer->OCMD & 0x1) 240 return true; 241 242 backBuffer->OCMD |= 0x1; 243 } 244 245 // flush 246 flush(PLANE_ENABLE); 247 return true; 248} 249 250bool OverlayPlaneBase::disable() 251{ 252 RETURN_FALSE_IF_NOT_INIT(); 253 for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) { 254 OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf; 255 if (!backBuffer) 256 return false; 257 258 if (!(backBuffer->OCMD & 0x1)) 259 return true; 260 261 backBuffer->OCMD &= ~0x1; 262 } 263 264 // flush 265 flush(PLANE_DISABLE); 266 return true; 267} 268 269OverlayBackBuffer* OverlayPlaneBase::createBackBuffer() 270{ 271 CTRACE(); 272 273 // create back buffer 274 OverlayBackBuffer *backBuffer = (OverlayBackBuffer *)malloc(sizeof(OverlayBackBuffer)); 275 if (!backBuffer) { 276 ELOGTRACE("failed to allocate back buffer"); 277 return 0; 278 } 279 280 281 int size = sizeof(OverlayBackBufferBlk); 282 int alignment = 64 * 1024; 283 void *wsbmBufferObject = 0; 284 bool ret = mWsbm->allocateTTMBuffer(size, alignment, &wsbmBufferObject); 285 if (ret == false) { 286 ELOGTRACE("failed to allocate TTM buffer"); 287 return 0; 288 } 289 290 void *virtAddr = mWsbm->getCPUAddress(wsbmBufferObject); 291 uint32_t gttOffsetInPage = mWsbm->getGttOffset(wsbmBufferObject); 292 293 backBuffer->buf = (OverlayBackBufferBlk *)virtAddr; 294 backBuffer->gttOffsetInPage = gttOffsetInPage; 295 backBuffer->bufObject = (uint32_t)wsbmBufferObject; 296 297 VLOGTRACE("cpu %p, gtt %d", virtAddr, gttOffsetInPage); 298 299 return backBuffer; 300} 301 302void OverlayPlaneBase::deleteBackBuffer(int buf) 303{ 304 if (!mBackBuffer[buf]) 305 return; 306 307 void *wsbmBufferObject = (void *)mBackBuffer[buf]->bufObject; 308 bool ret = mWsbm->destroyTTMBuffer(wsbmBufferObject); 309 if (ret == false) { 310 WLOGTRACE("failed to destroy TTM buffer"); 311 } 312 // free back buffer 313 free(mBackBuffer[buf]); 314 mBackBuffer[buf] = 0; 315} 316 317void OverlayPlaneBase::resetBackBuffer(int buf) 318{ 319 CTRACE(); 320 321 if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf) 322 return; 323 324 OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf; 325 326 memset(backBuffer, 0, sizeof(OverlayBackBufferBlk)); 327 328 // reset overlay 329 backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) | 330 (OVERLAY_INIT_BRIGHTNESS & 0xff); 331 backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION; 332 backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY; 333 backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK; 334 backBuffer->OCONFIG = 0; 335 backBuffer->OCONFIG |= (0x1 << 3); 336 backBuffer->OCONFIG |= (0x1 << 27); 337 backBuffer->SCHRKEN &= ~(0x7 << 24); 338 backBuffer->SCHRKEN |= 0xff; 339} 340 341BufferMapper* OverlayPlaneBase::getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload) 342{ 343 uint32_t khandle; 344 uint32_t w, h; 345 uint32_t yStride, uvStride; 346 stride_t stride; 347 int srcX, srcY, srcW, srcH; 348 int tmp; 349 350 DataBuffer *buf; 351 ssize_t index; 352 TTMBufferMapper *mapper; 353 bool ret; 354 355 if (!payload) { 356 ELOGTRACE("invalid payload buffer"); 357 return 0; 358 } 359 360 srcX = grallocMapper.getCrop().x; 361 srcY = grallocMapper.getCrop().y; 362 srcW = grallocMapper.getCrop().w; 363 srcH = grallocMapper.getCrop().h; 364 365 // init ttm buffer 366 khandle = payload->rotated_buffer_handle; 367 index = mTTMBuffers.indexOfKey(khandle); 368 if (index < 0) { 369 VLOGTRACE("unmapped TTM buffer, will map it"); 370 371 w = payload->rotated_width; 372 h = payload->rotated_height; 373 checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); 374 375 uint32_t format = grallocMapper.getFormat(); 376 // this is for sw decode with tiled buffer in landscape mode 377 if (payload->tiling) 378 format = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled; 379 380 // calculate stride 381 switch (format) { 382 case HAL_PIXEL_FORMAT_YV12: 383 case HAL_PIXEL_FORMAT_I420: 384 uint32_t yStride_align; 385 yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(grallocMapper.getFormat()); 386 if (yStride_align > 0) 387 { 388 yStride = align_to(align_to(w, 32), yStride_align); 389 } 390 else 391 { 392 yStride = align_to(align_to(w, 32), 64); 393 } 394 uvStride = align_to(yStride >> 1, 64); 395 stride.yuv.yStride = yStride; 396 stride.yuv.uvStride = uvStride; 397 break; 398 case HAL_PIXEL_FORMAT_NV12: 399 yStride = align_to(align_to(w, 32), 64); 400 uvStride = yStride; 401 stride.yuv.yStride = yStride; 402 stride.yuv.uvStride = uvStride; 403 break; 404 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: 405 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: 406 yStride = align_to(align_to(w, 32), 64); 407 uvStride = yStride; 408 stride.yuv.yStride = yStride; 409 stride.yuv.uvStride = uvStride; 410 break; 411 case HAL_PIXEL_FORMAT_YUY2: 412 case HAL_PIXEL_FORMAT_UYVY: 413 yStride = align_to((align_to(w, 32) << 1), 64); 414 uvStride = 0; 415 stride.yuv.yStride = yStride; 416 stride.yuv.uvStride = uvStride; 417 break; 418 } 419 420 DataBuffer buf(khandle); 421 // update buffer 422 buf.setStride(stride); 423 buf.setWidth(w); 424 buf.setHeight(h); 425 buf.setCrop(srcX, srcY, srcW, srcH); 426 buf.setFormat(format); 427 428 // create buffer mapper 429 bool res = false; 430 do { 431 mapper = new TTMBufferMapper(*mWsbm, buf); 432 if (!mapper) { 433 ELOGTRACE("failed to allocate mapper"); 434 break; 435 } 436 // map ttm buffer 437 ret = mapper->map(); 438 if (!ret) { 439 ELOGTRACE("failed to map"); 440 invalidateTTMBuffers(); 441 ret = mapper->map(); 442 if (!ret) { 443 ELOGTRACE("failed to remap"); 444 break; 445 } 446 } 447 448 if (mTTMBuffers.size() >= OVERLAY_DATA_BUFFER_COUNT) { 449 invalidateTTMBuffers(); 450 } 451 452 // add mapper 453 index = mTTMBuffers.add(khandle, mapper); 454 if (index < 0) { 455 ELOGTRACE("failed to add TTMMapper"); 456 break; 457 } 458 459 // increase mapper refCount since it is added to mTTMBuffers 460 mapper->incRef(); 461 res = true; 462 } while (0); 463 464 if (!res) { 465 // error handling 466 if (mapper) { 467 mapper->unmap(); 468 delete mapper; 469 mapper = NULL; 470 } 471 return 0; 472 } 473 } else { 474 VLOGTRACE("got mapper in saved ttm buffers"); 475 mapper = reinterpret_cast<TTMBufferMapper *>(mTTMBuffers.valueAt(index)); 476 if (mapper->getCrop().x != srcX || mapper->getCrop().y != srcY || 477 mapper->getCrop().w != srcW || mapper->getCrop().h != srcH) { 478 checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height); 479 mapper->setCrop(srcX, srcY, srcW, srcH); 480 } 481 } 482 483 XLOGTRACE(); 484 return mapper; 485} 486 487void OverlayPlaneBase::putTTMMapper(BufferMapper* mapper) 488{ 489 if (!mapper) 490 return; 491 492 if (!mapper->decRef()) { 493 // unmap it 494 mapper->unmap(); 495 496 // destroy this mapper 497 delete mapper; 498 } 499} 500 501bool OverlayPlaneBase::isActiveTTMBuffer(BufferMapper *mapper) 502{ 503 for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { 504 BufferMapper *activeMapper = mActiveTTMBuffers.itemAt(i); 505 if (!activeMapper) 506 continue; 507 if (activeMapper->getKey() == mapper->getKey()) 508 return true; 509 } 510 511 return false; 512} 513 514void OverlayPlaneBase::updateActiveTTMBuffers(BufferMapper *mapper) 515{ 516 // unmap the first entry (oldest buffer) 517 if (mActiveTTMBuffers.size() >= MAX_ACTIVE_TTM_BUFFERS) { 518 BufferMapper *oldest = mActiveTTMBuffers.itemAt(0); 519 putTTMMapper(oldest); 520 mActiveTTMBuffers.removeAt(0); 521 } 522 523 // queue it to cached buffers 524 if (!isActiveTTMBuffer(mapper)) { 525 mapper->incRef(); 526 mActiveTTMBuffers.push_back(mapper); 527 } 528} 529 530void OverlayPlaneBase::invalidateActiveTTMBuffers() 531{ 532 BufferMapper* mapper; 533 534 RETURN_VOID_IF_NOT_INIT(); 535 536 for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) { 537 mapper = mActiveTTMBuffers.itemAt(i); 538 // unmap it 539 putTTMMapper(mapper); 540 } 541 542 // clear recorded data buffers 543 mActiveTTMBuffers.clear(); 544} 545 546void OverlayPlaneBase::invalidateTTMBuffers() 547{ 548 BufferMapper* mapper; 549 for (size_t i = 0; i < mTTMBuffers.size(); i++) { 550 mapper = mTTMBuffers.valueAt(i); 551 // putTTMMapper removes mapper from cache 552 putTTMMapper(mapper); 553 } 554 mTTMBuffers.clear(); 555} 556 557 558bool OverlayPlaneBase::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper) 559{ 560 struct VideoPayloadBuffer *payload; 561 uint32_t format; 562 563 // only NV12_VED has rotated buffer 564 format = mapper.getFormat(); 565 if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar && 566 format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) 567 return false; 568 569 payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1); 570 // check payload 571 if (!payload) { 572 ELOGTRACE("no payload found"); 573 return false; 574 } 575 576 if (payload->force_output_method == FORCE_OUTPUT_GPU) 577 return false; 578 579 if (payload->client_transform != mTransform) { 580 if (payload->surface_protected) { 581 payload->hwc_timestamp = systemTime(); 582 payload->layer_transform = mTransform; 583 } 584 WLOGTRACE("client is not ready"); 585 return false; 586 } 587 588 rotatedMapper = getTTMMapper(mapper, payload); 589 return true; 590} 591 592 593bool OverlayPlaneBase::useOverlayRotation(BufferMapper& /* mapper */) 594{ 595 // by default overlay plane does not support rotation. 596 return false; 597} 598 599void OverlayPlaneBase::checkPosition(int& x, int& y, int& w, int& h) 600{ 601 drmModeModeInfoPtr mode = &mModeInfo; 602 603 if (mode->hdisplay == 0 || mode->vdisplay == 0) 604 return; 605 606 if (x < 0) 607 x = 0; 608 if (y < 0) 609 y = 0; 610 if ((x + w) > mode->hdisplay) 611 w = mode->hdisplay - x; 612 if ((y + h) > mode->vdisplay) 613 h = mode->vdisplay - y; 614} 615 616void OverlayPlaneBase::checkCrop(int& srcX, int& srcY, int& srcW, int& srcH, 617 int coded_width, int coded_height) 618{ 619 int tmp; 620 621 if (mTransform) 622 srcH >>= mBobDeinterlace; 623 624 if (mTransform == HWC_TRANSFORM_ROT_90 || mTransform == HWC_TRANSFORM_ROT_270) { 625 tmp = srcH; 626 srcH = srcW; 627 srcW = tmp; 628 629 tmp = srcX; 630 srcX = srcY; 631 srcY = tmp; 632 633 tmp = coded_width; 634 coded_width = coded_height; 635 coded_height = tmp; 636 } 637 638 // skip pading bytes in rotate buffer 639 switch(mTransform) { 640 case HWC_TRANSFORM_ROT_90: 641 srcX = (coded_width >> mBobDeinterlace) - srcW - srcX; 642 break; 643 case HWC_TRANSFORM_ROT_180: 644 srcX = coded_width - srcW - srcX; 645 srcY = (coded_height >> mBobDeinterlace) - srcH - srcY; 646 break; 647 case HWC_TRANSFORM_ROT_270: 648 srcY = coded_height - srcH - srcY; 649 break; 650 default: 651 break; 652 } 653} 654 655 656bool OverlayPlaneBase::bufferOffsetSetup(BufferMapper& mapper) 657{ 658 CTRACE(); 659 660 OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; 661 if (!backBuffer) { 662 ELOGTRACE("invalid back buffer"); 663 return false; 664 } 665 666 uint32_t format = mapper.getFormat(); 667 uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12); 668 uint32_t yStride = mapper.getStride().yuv.yStride; 669 uint32_t uvStride = mapper.getStride().yuv.uvStride; 670 uint32_t w = mapper.getWidth(); 671 uint32_t h = mapper.getHeight(); 672 uint32_t srcX= mapper.getCrop().x; 673 uint32_t srcY= mapper.getCrop().y; 674 675 // clear original format setting 676 backBuffer->OCMD &= ~(0xf << 10); 677 backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED; 678 679 // Y/U/V plane must be 4k bytes aligned. 680 backBuffer->OSTART_0Y = gttOffsetInBytes; 681 if (mIsProtectedBuffer) { 682 // temporary workaround until vsync event logic is corrected. 683 // it seems that overlay buffer update and renderring can be overlapped, 684 // as such encryption bit may be cleared during HW rendering 685 backBuffer->OSTART_0Y |= 0x01; 686 } 687 688 backBuffer->OSTART_0U = gttOffsetInBytes; 689 backBuffer->OSTART_0V = gttOffsetInBytes; 690 691 backBuffer->OSTART_1Y = backBuffer->OSTART_0Y; 692 backBuffer->OSTART_1U = backBuffer->OSTART_0U; 693 backBuffer->OSTART_1V = backBuffer->OSTART_0V; 694 695 switch(format) { 696 case HAL_PIXEL_FORMAT_YV12: // YV12 697 backBuffer->OBUF_0Y = 0; 698 backBuffer->OBUF_0V = yStride * h; 699 backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (h / 2)); 700 backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; 701 break; 702 case HAL_PIXEL_FORMAT_I420: // I420 703 backBuffer->OBUF_0Y = 0; 704 backBuffer->OBUF_0U = yStride * h; 705 backBuffer->OBUF_0V = backBuffer->OBUF_0U + (uvStride * (h / 2)); 706 backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420; 707 break; 708 case HAL_PIXEL_FORMAT_NV12: // NV12 709 backBuffer->OBUF_0Y = 0; 710 backBuffer->OBUF_0U = yStride * h; 711 backBuffer->OBUF_0V = 0; 712 backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; 713 break; 714 // NOTE: this is the decoded video format, align the height to 32B 715 //as it's defined by video driver 716 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // Intel codec NV12 717 backBuffer->OBUF_0Y = 0; 718 backBuffer->OBUF_0U = yStride * align_to(h, 32); 719 backBuffer->OBUF_0V = 0; 720 backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; 721 break; 722 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: //NV12_tiled 723 backBuffer->OBUF_0Y = 0; 724 backBuffer->OBUF_0U = yStride * align_to(h, 32); 725 backBuffer->OBUF_0V = 0; 726 backBuffer->OSTART_0U += yStride * align_to(h, 32); 727 backBuffer->OSTART_0V += yStride * align_to(h, 32); 728 backBuffer->OSTART_1U = backBuffer->OSTART_0U; 729 backBuffer->OSTART_1V = backBuffer->OSTART_0V; 730 backBuffer->OTILEOFF_0Y = srcX + (srcY << 16); 731 backBuffer->OTILEOFF_1Y = backBuffer->OTILEOFF_0Y; 732 backBuffer->OTILEOFF_0U = srcX + ((srcY / 2) << 16); 733 backBuffer->OTILEOFF_1U = backBuffer->OTILEOFF_0U; 734 backBuffer->OTILEOFF_0V = backBuffer->OTILEOFF_0U; 735 backBuffer->OTILEOFF_1V = backBuffer->OTILEOFF_0U; 736 backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2; 737 backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED; 738 break; 739 case HAL_PIXEL_FORMAT_YUY2: // YUY2 740 backBuffer->OBUF_0Y = 0; 741 backBuffer->OBUF_0U = 0; 742 backBuffer->OBUF_0V = 0; 743 backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; 744 backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2; 745 break; 746 case HAL_PIXEL_FORMAT_UYVY: // UYVY 747 backBuffer->OBUF_0Y = 0; 748 backBuffer->OBUF_0U = 0; 749 backBuffer->OBUF_0V = 0; 750 backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422; 751 backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY; 752 break; 753 default: 754 ELOGTRACE("unsupported format %d", format); 755 return false; 756 } 757 758 backBuffer->OBUF_0Y += srcY * yStride + srcX; 759 backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX; 760 backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX; 761 backBuffer->OBUF_1Y = backBuffer->OBUF_0Y; 762 backBuffer->OBUF_1U = backBuffer->OBUF_0U; 763 backBuffer->OBUF_1V = backBuffer->OBUF_0V; 764 765 VLOGTRACE("done. offset (%d, %d, %d)", 766 backBuffer->OBUF_0Y, 767 backBuffer->OBUF_0U, 768 backBuffer->OBUF_0V); 769 return true; 770} 771 772uint32_t OverlayPlaneBase::calculateSWidthSW(uint32_t offset, uint32_t width) 773{ 774 ALOGTRACE("offset = %d, width = %d", offset, width); 775 776 uint32_t swidth = ((offset + width + 0x3F) >> 6) - (offset >> 6); 777 778 swidth <<= 1; 779 swidth -= 1; 780 781 return swidth; 782} 783 784bool OverlayPlaneBase::coordinateSetup(BufferMapper& mapper) 785{ 786 CTRACE(); 787 788 OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; 789 if (!backBuffer) { 790 ELOGTRACE("invalid back buffer"); 791 return false; 792 } 793 794 uint32_t swidthy = 0; 795 uint32_t swidthuv = 0; 796 uint32_t format = mapper.getFormat(); 797 uint32_t width = mapper.getCrop().w; 798 uint32_t height = mapper.getCrop().h; 799 uint32_t yStride = mapper.getStride().yuv.yStride; 800 uint32_t uvStride = mapper.getStride().yuv.uvStride; 801 uint32_t offsety = backBuffer->OBUF_0Y; 802 uint32_t offsetu = backBuffer->OBUF_0U; 803 804 switch (format) { 805 case HAL_PIXEL_FORMAT_YV12: // YV12 806 case HAL_PIXEL_FORMAT_I420: // I420 807 case HAL_PIXEL_FORMAT_NV12: // NV12 808 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar: // NV12 809 case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled: // NV12_tiled 810 break; 811 case HAL_PIXEL_FORMAT_YUY2: // YUY2 812 case HAL_PIXEL_FORMAT_UYVY: // UYVY 813 width <<= 1; 814 break; 815 default: 816 ELOGTRACE("unsupported format %d", format); 817 return false; 818 } 819 820 if (width <= 0 || height <= 0) { 821 ELOGTRACE("invalid src dim"); 822 return false; 823 } 824 825 if (yStride <=0 && uvStride <= 0) { 826 ELOGTRACE("invalid source stride"); 827 return false; 828 } 829 830 backBuffer->SWIDTH = width | ((width / 2) << 16); 831 swidthy = calculateSWidthSW(offsety, width); 832 swidthuv = calculateSWidthSW(offsetu, width / 2); 833 backBuffer->SWIDTHSW = (swidthy << 2) | (swidthuv << 18); 834 backBuffer->SHEIGHT = height | ((height / 2) << 16); 835 backBuffer->OSTRIDE = (yStride & (~0x3f)) | ((uvStride & (~0x3f)) << 16); 836 837 XLOGTRACE(); 838 839 return true; 840} 841 842bool OverlayPlaneBase::setCoeffRegs(double *coeff, int mantSize, 843 coeffPtr pCoeff, int pos) 844{ 845 int maxVal, icoeff, res; 846 int sign; 847 double c; 848 849 sign = 0; 850 maxVal = 1 << mantSize; 851 c = *coeff; 852 if (c < 0.0) { 853 sign = 1; 854 c = -c; 855 } 856 857 res = 12 - mantSize; 858 if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) { 859 pCoeff[pos].exponent = 3; 860 pCoeff[pos].mantissa = icoeff << res; 861 *coeff = (double)icoeff / (double)(4 * maxVal); 862 } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) { 863 pCoeff[pos].exponent = 2; 864 pCoeff[pos].mantissa = icoeff << res; 865 *coeff = (double)icoeff / (double)(2 * maxVal); 866 } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) { 867 pCoeff[pos].exponent = 1; 868 pCoeff[pos].mantissa = icoeff << res; 869 *coeff = (double)icoeff / (double)(maxVal); 870 } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) { 871 pCoeff[pos].exponent = 0; 872 pCoeff[pos].mantissa = icoeff << res; 873 *coeff = (double)icoeff / (double)(maxVal / 2); 874 } else { 875 // Coeff out of range 876 return false; 877 } 878 879 pCoeff[pos].sign = sign; 880 if (sign) 881 *coeff = -(*coeff); 882 return true; 883} 884 885void OverlayPlaneBase::updateCoeff(int taps, double fCutoff, 886 bool isHoriz, bool isY, 887 coeffPtr pCoeff) 888{ 889 int i, j, j1, num, pos, mantSize; 890 double pi = 3.1415926535, val, sinc, window, sum; 891 double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS]; 892 double diff; 893 int tapAdjust[MAX_TAPS], tap2Fix; 894 bool isVertAndUV; 895 896 if (isHoriz) 897 mantSize = 7; 898 else 899 mantSize = 6; 900 901 isVertAndUV = !isHoriz && !isY; 902 num = taps * 16; 903 for (i = 0; i < num * 2; i++) { 904 val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num); 905 if (val == 0.0) 906 sinc = 1.0; 907 else 908 sinc = sin(val) / val; 909 910 // Hamming window 911 window = (0.54 - 0.46 * cos(2 * i * pi / (2 * num - 1))); 912 rawCoeff[i] = sinc * window; 913 } 914 915 for (i = 0; i < N_PHASES; i++) { 916 // Normalise the coefficients 917 sum = 0.0; 918 for (j = 0; j < taps; j++) { 919 pos = i + j * 32; 920 sum += rawCoeff[pos]; 921 } 922 for (j = 0; j < taps; j++) { 923 pos = i + j * 32; 924 coeffs[i][j] = rawCoeff[pos] / sum; 925 } 926 927 // Set the register values 928 for (j = 0; j < taps; j++) { 929 pos = j + i * taps; 930 if ((j == (taps - 1) / 2) && !isVertAndUV) 931 setCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos); 932 else 933 setCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos); 934 } 935 936 tapAdjust[0] = (taps - 1) / 2; 937 for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) { 938 tapAdjust[j1] = tapAdjust[0] - j; 939 tapAdjust[++j1] = tapAdjust[0] + j; 940 } 941 942 // Adjust the coefficients 943 sum = 0.0; 944 for (j = 0; j < taps; j++) 945 sum += coeffs[i][j]; 946 if (sum != 1.0) { 947 for (j1 = 0; j1 < taps; j1++) { 948 tap2Fix = tapAdjust[j1]; 949 diff = 1.0 - sum; 950 coeffs[i][tap2Fix] += diff; 951 pos = tap2Fix + i * taps; 952 if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV) 953 setCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos); 954 else 955 setCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos); 956 957 sum = 0.0; 958 for (j = 0; j < taps; j++) 959 sum += coeffs[i][j]; 960 if (sum == 1.0) 961 break; 962 } 963 } 964 } 965} 966 967bool OverlayPlaneBase::scalingSetup(BufferMapper& mapper) 968{ 969 int xscaleInt, xscaleFract, yscaleInt, yscaleFract; 970 int xscaleIntUV, xscaleFractUV; 971 int yscaleIntUV, yscaleFractUV; 972 int deinterlace_factor = 1; 973 // UV is half the size of Y -- YUV420 974 int uvratio = 2; 975 uint32_t newval; 976 coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES]; 977 coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES]; 978 int i, j, pos; 979 bool scaleChanged = false; 980 int x, y, w, h; 981 982 OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; 983 if (!backBuffer) { 984 ELOGTRACE("invalid back buffer"); 985 return false; 986 } 987 988 x = mPosition.x; 989 y = mPosition.y; 990 w = mPosition.w; 991 h = mPosition.h; 992 993 // check position 994 checkPosition(x, y, w, h); 995 VLOGTRACE("final position (%d, %d, %d, %d)", x, y, w, h); 996 997 if ((w <= 0) || (h <= 0)) { 998 ELOGTRACE("invalid dst width/height"); 999 return false; 1000 } 1001 1002 // setup dst position 1003 backBuffer->DWINPOS = (y << 16) | x; 1004 backBuffer->DWINSZ = (h << 16) | w; 1005 1006 uint32_t srcWidth = mapper.getCrop().w; 1007 uint32_t srcHeight = mapper.getCrop().h; 1008 uint32_t dstWidth = w; 1009 uint32_t dstHeight = h; 1010 1011 VLOGTRACE("src (%dx%d), dst (%dx%d)", 1012 srcWidth, srcHeight, 1013 dstWidth, dstHeight); 1014 1015 // Y down-scale factor as a multiple of 4096 1016 if (srcWidth == dstWidth && srcHeight == dstHeight) { 1017 xscaleFract = (1 << 12); 1018 yscaleFract = (1 << 12)/deinterlace_factor; 1019 } else { 1020 xscaleFract = ((srcWidth - 1) << 12) / dstWidth; 1021 yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor); 1022 } 1023 1024 // Calculate the UV scaling factor 1025 xscaleFractUV = xscaleFract / uvratio; 1026 yscaleFractUV = yscaleFract / uvratio; 1027 1028 // To keep the relative Y and UV ratios exact, round the Y scales 1029 // to a multiple of the Y/UV ratio. 1030 xscaleFract = xscaleFractUV * uvratio; 1031 yscaleFract = yscaleFractUV * uvratio; 1032 1033 // Integer (un-multiplied) values 1034 xscaleInt = xscaleFract >> 12; 1035 yscaleInt = yscaleFract >> 12; 1036 1037 xscaleIntUV = xscaleFractUV >> 12; 1038 yscaleIntUV = yscaleFractUV >> 12; 1039 1040 // Check scaling ratio 1041 if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) { 1042 ELOGTRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); 1043 return false; 1044 } 1045 1046 // shouldn't get here 1047 if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) { 1048 ELOGTRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO); 1049 return false; 1050 } 1051 1052 newval = (xscaleInt << 15) | 1053 ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); 1054 if (newval != backBuffer->YRGBSCALE) { 1055 scaleChanged = true; 1056 backBuffer->YRGBSCALE = newval; 1057 } 1058 1059 newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) | 1060 ((yscaleFractUV & 0xFFF) << 20); 1061 if (newval != backBuffer->UVSCALE) { 1062 scaleChanged = true; 1063 backBuffer->UVSCALE = newval; 1064 } 1065 1066 newval = yscaleInt << 16 | yscaleIntUV; 1067 if (newval != backBuffer->UVSCALEV) { 1068 scaleChanged = true; 1069 backBuffer->UVSCALEV = newval; 1070 } 1071 1072 // Recalculate coefficients if the scaling changed 1073 // Only Horizontal coefficients so far. 1074 if (scaleChanged) { 1075 double fCutoffY; 1076 double fCutoffUV; 1077 1078 fCutoffY = xscaleFract / 4096.0; 1079 fCutoffUV = xscaleFractUV / 4096.0; 1080 1081 // Limit to between 1.0 and 3.0 1082 if (fCutoffY < MIN_CUTOFF_FREQ) 1083 fCutoffY = MIN_CUTOFF_FREQ; 1084 if (fCutoffY > MAX_CUTOFF_FREQ) 1085 fCutoffY = MAX_CUTOFF_FREQ; 1086 if (fCutoffUV < MIN_CUTOFF_FREQ) 1087 fCutoffUV = MIN_CUTOFF_FREQ; 1088 if (fCutoffUV > MAX_CUTOFF_FREQ) 1089 fCutoffUV = MAX_CUTOFF_FREQ; 1090 1091 updateCoeff(N_HORIZ_Y_TAPS, fCutoffY, true, true, xcoeffY); 1092 updateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, true, false, xcoeffUV); 1093 1094 for (i = 0; i < N_PHASES; i++) { 1095 for (j = 0; j < N_HORIZ_Y_TAPS; j++) { 1096 pos = i * N_HORIZ_Y_TAPS + j; 1097 backBuffer->Y_HCOEFS[pos] = 1098 (xcoeffY[pos].sign << 15 | 1099 xcoeffY[pos].exponent << 12 | 1100 xcoeffY[pos].mantissa); 1101 } 1102 } 1103 for (i = 0; i < N_PHASES; i++) { 1104 for (j = 0; j < N_HORIZ_UV_TAPS; j++) { 1105 pos = i * N_HORIZ_UV_TAPS + j; 1106 backBuffer->UV_HCOEFS[pos] = 1107 (xcoeffUV[pos].sign << 15 | 1108 xcoeffUV[pos].exponent << 12 | 1109 xcoeffUV[pos].mantissa); 1110 } 1111 } 1112 } 1113 1114 XLOGTRACE(); 1115 return true; 1116} 1117 1118bool OverlayPlaneBase::setDataBuffer(BufferMapper& grallocMapper) 1119{ 1120 BufferMapper *mapper; 1121 BufferMapper *rotatedMapper = 0; 1122 bool ret; 1123 uint32_t format; 1124 1125 RETURN_FALSE_IF_NOT_INIT(); 1126 1127 // get gralloc mapper 1128 mapper = &grallocMapper; 1129 format = grallocMapper.getFormat(); 1130 if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar || 1131 format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) { 1132 struct VideoPayloadBuffer *payload; 1133 payload = (struct VideoPayloadBuffer *)grallocMapper.getCpuAddress(SUB_BUFFER1); 1134 if (!payload) { 1135 ELOGTRACE("invalid payload buffer"); 1136 return 0; 1137 } 1138 1139 mBobDeinterlace = payload->bob_deinterlace; 1140 } 1141 1142 if (mTransform && !useOverlayRotation(grallocMapper)) { 1143 if (!rotatedBufferReady(grallocMapper, rotatedMapper)) { 1144 DLOGTRACE("rotated buffer is not ready"); 1145 return false; 1146 } 1147 1148 if (!rotatedMapper) { 1149 ELOGTRACE("failed to get rotated buffer"); 1150 return false; 1151 } 1152 mapper = rotatedMapper; 1153 } 1154 1155 OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf; 1156 if (!backBuffer) { 1157 ELOGTRACE("invalid back buffer"); 1158 return false; 1159 } 1160 1161 ret = bufferOffsetSetup(*mapper); 1162 if (ret == false) { 1163 ELOGTRACE("failed to set up buffer offsets"); 1164 return false; 1165 } 1166 1167 ret = coordinateSetup(*mapper); 1168 if (ret == false) { 1169 ELOGTRACE("failed to set up overlay coordinates"); 1170 return false; 1171 } 1172 1173 ret = scalingSetup(*mapper); 1174 if (ret == false) { 1175 ELOGTRACE("failed to set up scaling parameters"); 1176 return false; 1177 } 1178 1179 backBuffer->OCMD |= 0x1; 1180 1181 if (mBobDeinterlace && !mTransform) { 1182 backBuffer->OCMD |= BUF_TYPE_FIELD; 1183 backBuffer->OCMD &= ~FIELD_SELECT; 1184 backBuffer->OCMD |= FIELD0; 1185 backBuffer->OCMD &= ~(BUFFER_SELECT); 1186 backBuffer->OCMD |= BUFFER0; 1187 } 1188 1189 // add to active ttm buffers if it's a rotated buffer 1190 if (rotatedMapper) { 1191 updateActiveTTMBuffers(mapper); 1192 } 1193 1194 return true; 1195} 1196 1197} // namespace intel 1198} // namespace android 1199 1200