1 /* 2 // Copyright(c)2014 IntelCorporation 3 // 4 // LicensedundertheApacheLicense,Version2.0(the"License"); 5 // youmaynotusethisfileexceptincompliancewiththeLicense. 6 // YoumayobtainacopyoftheLicenseat 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software 11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS, 12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. 13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand 14 // limitationsundertheLicense. 15 */ 16 17 #include <HwcTrace.h> 18 #include <common/RotationBufferProvider.h> 19 #include <system/graphics-base.h> 20 21 namespace android { 22 namespace intel { 23 24 #define CHECK_VA_STATUS_RETURN(FUNC) \ 25 if (vaStatus != VA_STATUS_SUCCESS) {\ 26 ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\ 27 return false;\ 28 } 29 30 #define CHECK_VA_STATUS_BREAK(FUNC) \ 31 if (vaStatus != VA_STATUS_SUCCESS) {\ 32 ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\ 33 break;\ 34 } 35 36 // With this display value, VA will hook VED driver insead of VSP driver for buffer rotation 37 #define DISPLAYVALUE 0x56454450 38 39 RotationBufferProvider::RotationBufferProvider(Wsbm* wsbm) 40 : mWsbm(wsbm), 41 mVaInitialized(false), 42 mVaDpy(0), 43 mVaCfg(0), 44 mVaCtx(0), 45 mVaBufFilter(0), 46 mSourceSurface(0), 47 mDisplay(DISPLAYVALUE), 48 mWidth(0), 49 mHeight(0), 50 mTransform(0), 51 mRotatedWidth(0), 52 mRotatedHeight(0), 53 mRotatedStride(0), 54 mTargetIndex(0), 55 mTTMWrappers(), 56 mBobDeinterlace(0) 57 { 58 for (int i = 0; i < MAX_SURFACE_NUM; i++) { 59 mKhandles[i] = 0; 60 mRotatedSurfaces[i] = 0; 61 mDrmBuf[i] = NULL; 62 } 63 } 64 65 RotationBufferProvider::~RotationBufferProvider() 66 { 67 } 68 69 uint32_t RotationBufferProvider::getMilliseconds() 70 { 71 struct timeval ptimeval; 72 gettimeofday(&ptimeval, NULL); 73 return (uint32_t)((ptimeval.tv_sec * 1000) + (ptimeval.tv_usec / 1000)); 74 } 75 76 bool RotationBufferProvider::initialize() 77 { 78 if (NULL == mWsbm) 79 return false; 80 mTTMWrappers.setCapacity(TTM_WRAPPER_COUNT); 81 return true; 82 } 83 84 void RotationBufferProvider::deinitialize() 85 { 86 stopVA(); 87 reset(); 88 } 89 90 void RotationBufferProvider::reset() 91 { 92 if (mTTMWrappers.size()) { 93 invalidateCaches(); 94 } 95 } 96 97 void RotationBufferProvider::invalidateCaches() 98 { 99 void *buf; 100 101 for (size_t i = 0; i < mTTMWrappers.size(); i++) { 102 buf = mTTMWrappers.valueAt(i); 103 if (!mWsbm->destroyTTMBuffer(buf)) 104 WTRACE("failed to free TTMBuffer"); 105 } 106 mTTMWrappers.clear(); 107 } 108 109 int RotationBufferProvider::transFromHalToVa(int transform) 110 { 111 if (transform == HAL_TRANSFORM_ROT_90) 112 return VA_ROTATION_90; 113 if (transform == HAL_TRANSFORM_ROT_180) 114 return VA_ROTATION_180; 115 if (transform == HAL_TRANSFORM_ROT_270) 116 return VA_ROTATION_270; 117 return 0; 118 } 119 120 int RotationBufferProvider::getStride(bool isTarget, int width) 121 { 122 int stride = 0; 123 if (width <= 512) 124 stride = 512; 125 else if (width <= 1024) 126 stride = 1024; 127 else if (width <= 1280) { 128 stride = 1280; 129 if (isTarget) 130 stride = 2048; 131 } else if (width <= 2048) 132 stride = 2048; 133 else if (width <= 4096) 134 stride = 4096; 135 else 136 stride = (width + 0x3f) & ~0x3f; 137 return stride; 138 } 139 140 buffer_handle_t RotationBufferProvider::createWsbmBuffer(int width, int height, void **buf) 141 { 142 int size = width * height * 3 / 2; // YUV420 NV12 format 143 int allignment = 16 * 2048; // tiling row stride aligned 144 bool ret = mWsbm->allocateTTMBuffer(size, allignment, buf); 145 146 if (ret == false) { 147 ETRACE("failed to allocate TTM buffer"); 148 return 0; 149 } 150 151 return (buffer_handle_t) mWsbm->getKBufHandle(*buf); 152 } 153 154 bool RotationBufferProvider::createVaSurface(VideoPayloadBuffer *payload, int transform, bool isTarget) 155 { 156 VAStatus vaStatus; 157 VASurfaceAttributeTPI attribTpi; 158 VASurfaceAttributeTPI *vaSurfaceAttrib = &attribTpi; 159 int stride; 160 unsigned long buffers; 161 VASurfaceID *surface; 162 int width = 0, height = 0, bufferHeight = 0; 163 164 if (isTarget) { 165 if (transFromHalToVa(transform) == VA_ROTATION_180) { 166 width = payload->width; 167 height = payload->height; 168 } else { 169 width = payload->height; 170 height = payload->width; 171 } 172 mRotatedWidth = width; 173 mRotatedHeight = height; 174 bufferHeight = (height + 0x1f) & ~0x1f; 175 stride = getStride(isTarget, width); 176 } else { 177 width = payload->width; 178 height = payload->height; 179 bufferHeight = (payload->height + 0x1f) & ~0x1f; 180 stride = payload->luma_stride; /* NV12 srouce buffer */ 181 } 182 183 if (!stride) { 184 ETRACE("invalid stride value"); 185 return false; 186 } 187 188 mBobDeinterlace = payload->bob_deinterlace; 189 // adjust source target for Bob deinterlace 190 if (!isTarget && mBobDeinterlace) { 191 height >>= 1; 192 bufferHeight >>= 1; 193 stride <<= 1; 194 } 195 196 vaSurfaceAttrib->count = 1; 197 vaSurfaceAttrib->width = width; 198 vaSurfaceAttrib->height = height; 199 vaSurfaceAttrib->pixel_format = payload->format; 200 vaSurfaceAttrib->type = VAExternalMemoryKernelDRMBufffer; 201 vaSurfaceAttrib->tiling = payload->tiling; 202 vaSurfaceAttrib->size = (stride * bufferHeight * 3) / 2; 203 vaSurfaceAttrib->luma_offset = 0; 204 vaSurfaceAttrib->chroma_v_offset = stride * bufferHeight; 205 vaSurfaceAttrib->luma_stride = vaSurfaceAttrib->chroma_u_stride 206 = vaSurfaceAttrib->chroma_v_stride 207 = stride; 208 vaSurfaceAttrib->chroma_u_offset = vaSurfaceAttrib->chroma_v_offset; 209 vaSurfaceAttrib->buffers = &buffers; 210 211 if (isTarget) { 212 buffer_handle_t khandle = createWsbmBuffer(stride, bufferHeight, &mDrmBuf[mTargetIndex]); 213 if (khandle == 0) { 214 ETRACE("failed to create buffer by wsbm"); 215 return false; 216 } 217 218 mKhandles[mTargetIndex] = khandle; 219 vaSurfaceAttrib->buffers[0] = (uintptr_t) khandle; 220 mRotatedStride = stride; 221 surface = &mRotatedSurfaces[mTargetIndex]; 222 } else { 223 vaSurfaceAttrib->buffers[0] = (uintptr_t) payload->khandle; 224 surface = &mSourceSurface; 225 /* set src surface width/height to video crop size */ 226 if (payload->crop_width && payload->crop_height) { 227 width = payload->crop_width; 228 height = (payload->crop_height >> mBobDeinterlace); 229 } else { 230 VTRACE("Invalid cropping width or height"); 231 payload->crop_width = width; 232 payload->crop_height = height; 233 } 234 } 235 236 vaStatus = vaCreateSurfacesWithAttribute(mVaDpy, 237 width, 238 height, 239 VA_RT_FORMAT_YUV420, 240 1, 241 surface, 242 vaSurfaceAttrib); 243 if (vaStatus != VA_STATUS_SUCCESS) { 244 ETRACE("vaCreateSurfacesWithAttribute returns %d", vaStatus); 245 ETRACE("Attributes: target: %d, width: %d, height %d, bufferHeight %d, tiling %d", 246 isTarget, width, height, bufferHeight, payload->tiling); 247 *surface = 0; 248 return false; 249 } 250 251 return true; 252 } 253 254 bool RotationBufferProvider::startVA(VideoPayloadBuffer *payload, int transform) 255 { 256 bool ret = true; 257 VAStatus vaStatus; 258 VAEntrypoint *entryPoint; 259 VAConfigAttrib attribDummy; 260 int numEntryPoints; 261 bool supportVideoProcessing = false; 262 int majorVer = 0, minorVer = 0; 263 264 // VA will hold a copy of the param pointer, so local varialbe doesn't work 265 mVaDpy = vaGetDisplay(&mDisplay); 266 if (NULL == mVaDpy) { 267 ETRACE("failed to get VADisplay"); 268 return false; 269 } 270 271 vaStatus = vaInitialize(mVaDpy, &majorVer, &minorVer); 272 CHECK_VA_STATUS_RETURN("vaInitialize"); 273 274 numEntryPoints = vaMaxNumEntrypoints(mVaDpy); 275 276 if (numEntryPoints <= 0) { 277 ETRACE("numEntryPoints value is invalid"); 278 return false; 279 } 280 281 entryPoint = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * numEntryPoints); 282 if (NULL == entryPoint) { 283 ETRACE("failed to malloc memory for entryPoint"); 284 return false; 285 } 286 287 vaStatus = vaQueryConfigEntrypoints(mVaDpy, 288 VAProfileNone, 289 entryPoint, 290 &numEntryPoints); 291 CHECK_VA_STATUS_RETURN("vaQueryConfigEntrypoints"); 292 293 for (int i = 0; i < numEntryPoints; i++) 294 if (entryPoint[i] == VAEntrypointVideoProc) 295 supportVideoProcessing = true; 296 297 free(entryPoint); 298 entryPoint = NULL; 299 300 if (!supportVideoProcessing) { 301 ETRACE("VAEntrypointVideoProc is not supported"); 302 return false; 303 } 304 305 vaStatus = vaCreateConfig(mVaDpy, 306 VAProfileNone, 307 VAEntrypointVideoProc, 308 &attribDummy, 309 0, 310 &mVaCfg); 311 CHECK_VA_STATUS_RETURN("vaCreateConfig"); 312 313 // create first target surface 314 ret = createVaSurface(payload, transform, true); 315 if (ret == false) { 316 ETRACE("failed to create target surface with attribute"); 317 return false; 318 } 319 320 vaStatus = vaCreateContext(mVaDpy, 321 mVaCfg, 322 payload->width, 323 payload->height, 324 0, 325 &mRotatedSurfaces[0], 326 1, 327 &mVaCtx); 328 CHECK_VA_STATUS_RETURN("vaCreateContext"); 329 330 VAProcFilterType filters[VAProcFilterCount]; 331 unsigned int numFilters = VAProcFilterCount; 332 vaStatus = vaQueryVideoProcFilters(mVaDpy, mVaCtx, filters, &numFilters); 333 CHECK_VA_STATUS_RETURN("vaQueryVideoProcFilters"); 334 335 bool supportVideoProcFilter = false; 336 for (unsigned int j = 0; j < numFilters; j++) 337 if (filters[j] == VAProcFilterNone) 338 supportVideoProcFilter = true; 339 340 if (!supportVideoProcFilter) { 341 ETRACE("VAProcFilterNone is not supported"); 342 return false; 343 } 344 345 VAProcFilterParameterBuffer filter; 346 filter.type = VAProcFilterNone; 347 filter.value = 0; 348 349 vaStatus = vaCreateBuffer(mVaDpy, 350 mVaCtx, 351 VAProcFilterParameterBufferType, 352 sizeof(filter), 353 1, 354 &filter, 355 &mVaBufFilter); 356 CHECK_VA_STATUS_RETURN("vaCreateBuffer"); 357 358 VAProcPipelineCaps pipelineCaps; 359 unsigned int numCaps = 1; 360 vaStatus = vaQueryVideoProcPipelineCaps(mVaDpy, 361 mVaCtx, 362 &mVaBufFilter, 363 numCaps, 364 &pipelineCaps); 365 CHECK_VA_STATUS_RETURN("vaQueryVideoProcPipelineCaps"); 366 367 if (!(pipelineCaps.rotation_flags & (1 << transFromHalToVa(transform)))) { 368 ETRACE("VA_ROTATION_xxx: 0x%08x is not supported by the filter", 369 transFromHalToVa(transform)); 370 return false; 371 } 372 373 mVaInitialized = true; 374 375 return true; 376 } 377 378 bool RotationBufferProvider::setupRotationBuffer(VideoPayloadBuffer *payload, int transform) 379 { 380 #ifdef DEBUG_ROTATION_PERFROMANCE 381 uint32_t setup_Begin = getMilliseconds(); 382 #endif 383 VAStatus vaStatus; 384 int stride; 385 bool ret = false; 386 387 if (payload->format != VA_FOURCC_NV12 || payload->width == 0 || payload->height == 0) { 388 WTRACE("payload data is not correct: format %#x, width %d, height %d", 389 payload->format, payload->width, payload->height); 390 return ret; 391 } 392 393 if (payload->width > 1280 && payload->width <= 2048) { 394 payload->tiling = 1; 395 } 396 397 do { 398 if (isContextChanged(payload->width, payload->height, transform)) { 399 DTRACE("VA is restarted as rotation context changes"); 400 401 if (mVaInitialized) { 402 stopVA(); // need to re-initialize VA for new rotation config 403 } 404 mTransform = transform; 405 mWidth = payload->width; 406 mHeight = payload->height; 407 } 408 409 if (!mVaInitialized) { 410 ret = startVA(payload, transform); 411 if (ret == false) { 412 vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; 413 break; 414 } 415 } 416 417 // start to create next target surface 418 if (!mRotatedSurfaces[mTargetIndex]) { 419 ret = createVaSurface(payload, transform, true); 420 if (ret == false) { 421 ETRACE("failed to create target surface with attribute"); 422 vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; 423 break; 424 } 425 } 426 427 // create source surface 428 ret = createVaSurface(payload, transform, false); 429 if (ret == false) { 430 ETRACE("failed to create source surface with attribute"); 431 vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; 432 break; 433 } 434 435 #ifdef DEBUG_ROTATION_PERFROMANCE 436 uint32_t beginPicture = getMilliseconds(); 437 #endif 438 vaStatus = vaBeginPicture(mVaDpy, mVaCtx, mRotatedSurfaces[mTargetIndex]); 439 CHECK_VA_STATUS_BREAK("vaBeginPicture"); 440 441 VABufferID pipelineBuf; 442 void *p; 443 VAProcPipelineParameterBuffer *pipelineParam; 444 vaStatus = vaCreateBuffer(mVaDpy, 445 mVaCtx, 446 VAProcPipelineParameterBufferType, 447 sizeof(*pipelineParam), 448 1, 449 NULL, 450 &pipelineBuf); 451 CHECK_VA_STATUS_BREAK("vaCreateBuffer"); 452 453 vaStatus = vaMapBuffer(mVaDpy, pipelineBuf, &p); 454 CHECK_VA_STATUS_BREAK("vaMapBuffer"); 455 456 pipelineParam = (VAProcPipelineParameterBuffer*)p; 457 pipelineParam->surface = mSourceSurface; 458 pipelineParam->rotation_state = transFromHalToVa(transform); 459 pipelineParam->filters = &mVaBufFilter; 460 pipelineParam->num_filters = 1; 461 pipelineParam->surface_region = NULL; 462 pipelineParam->output_region = NULL; 463 pipelineParam->num_forward_references = 0; 464 pipelineParam->num_backward_references = 0; 465 vaStatus = vaUnmapBuffer(mVaDpy, pipelineBuf); 466 CHECK_VA_STATUS_BREAK("vaUnmapBuffer"); 467 468 vaStatus = vaRenderPicture(mVaDpy, mVaCtx, &pipelineBuf, 1); 469 CHECK_VA_STATUS_BREAK("vaRenderPicture"); 470 471 vaStatus = vaEndPicture(mVaDpy, mVaCtx); 472 CHECK_VA_STATUS_BREAK("vaEndPicture"); 473 474 vaStatus = vaSyncSurface(mVaDpy, mRotatedSurfaces[mTargetIndex]); 475 CHECK_VA_STATUS_BREAK("vaSyncSurface"); 476 477 #ifdef DEBUG_ROTATION_PERFROMANCE 478 ITRACE("time spent %dms from vaBeginPicture to vaSyncSurface", 479 getMilliseconds() - beginPicture); 480 #endif 481 482 // Populate payload fields so that overlayPlane can flip the buffer 483 payload->rotated_width = mRotatedStride; 484 payload->rotated_height = mRotatedHeight; 485 payload->rotated_buffer_handle = mKhandles[mTargetIndex]; 486 // setting client transform to 0 to force re-generating rotated buffer whenever needed. 487 payload->client_transform = 0; 488 mTargetIndex++; 489 if (mTargetIndex >= MAX_SURFACE_NUM) 490 mTargetIndex = 0; 491 492 } while (0); 493 494 #ifdef DEBUG_ROTATION_PERFROMANCE 495 ITRACE("time spent %dms for setupRotationBuffer", 496 getMilliseconds() - setup_Begin); 497 #endif 498 499 if (mSourceSurface > 0) { 500 vaStatus = vaDestroySurfaces(mVaDpy, &mSourceSurface, 1); 501 if (vaStatus != VA_STATUS_SUCCESS) 502 WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus); 503 mSourceSurface = 0; 504 } 505 506 if (vaStatus != VA_STATUS_SUCCESS) { 507 stopVA(); 508 return false; // To not block HWC, just abort instead of retry 509 } 510 511 if (!payload->khandle) { 512 WTRACE("khandle is reset by decoder, surface is invalid!"); 513 return false; 514 } 515 516 return true; 517 } 518 519 bool RotationBufferProvider::prepareBufferInfo(int w, int h, int stride, VideoPayloadBuffer *payload, void *user_pt) 520 { 521 int chroma_offset, size; 522 void *buf = NULL; 523 524 payload->width = payload->crop_width = w; 525 payload->height = payload->crop_height = h; 526 payload->coded_width = ((w + 0xf) & ~0xf); 527 payload->coded_height = ((h + 0xf) & ~0xf); 528 payload->format = VA_FOURCC_NV12; 529 payload->tiling = 1; 530 payload->luma_stride = stride; 531 payload->chroma_u_stride = stride; 532 payload->chroma_v_stride = stride; 533 payload->client_transform = 0; 534 payload->bob_deinterlace = 0; 535 536 chroma_offset = stride * h; 537 size = stride * h + stride * h / 2; 538 539 ssize_t index; 540 index = mTTMWrappers.indexOfKey((uint64_t)user_pt); 541 if (index < 0) { 542 VTRACE("wrapped userPt as wsbm buffer"); 543 bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt); 544 if (ret == false) { 545 ETRACE("failed to allocate TTM buffer"); 546 return ret; 547 } 548 549 if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) { 550 WTRACE("mTTMWrappers is unexpectedly full. Invalidate caches"); 551 invalidateCaches(); 552 } 553 554 index = mTTMWrappers.add((uint64_t)user_pt, buf); 555 } else { 556 VTRACE("got wsbmBuffer in saved caches"); 557 buf = mTTMWrappers.valueAt(index); 558 } 559 560 payload->khandle = (buffer_handle_t) mWsbm->getKBufHandle(buf); 561 return true; 562 } 563 564 void RotationBufferProvider::freeVaSurfaces() 565 { 566 bool ret; 567 VAStatus vaStatus; 568 569 for (int i = 0; i < MAX_SURFACE_NUM; i++) { 570 if (NULL != mDrmBuf[i]) { 571 ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]); 572 if (!ret) 573 WTRACE("failed to free TTMBuffer"); 574 mDrmBuf[i] = NULL; 575 } 576 } 577 578 // remove wsbm buffer ref from VA 579 for (int j = 0; j < MAX_SURFACE_NUM; j++) { 580 if (0 != mRotatedSurfaces[j]) { 581 vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1); 582 if (vaStatus != VA_STATUS_SUCCESS) 583 WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus); 584 } 585 mRotatedSurfaces[j] = 0; 586 } 587 } 588 589 void RotationBufferProvider::stopVA() 590 { 591 freeVaSurfaces(); 592 593 if (0 != mVaBufFilter) 594 vaDestroyBuffer(mVaDpy, mVaBufFilter); 595 if (0 != mVaCfg) 596 vaDestroyConfig(mVaDpy,mVaCfg); 597 if (0 != mVaCtx) 598 vaDestroyContext(mVaDpy, mVaCtx); 599 if (0 != mVaDpy) 600 vaTerminate(mVaDpy); 601 602 mVaInitialized = false; 603 604 for (int i = 0; i < MAX_SURFACE_NUM; i++) { 605 mKhandles[i] = 0; 606 mRotatedSurfaces[i] = 0; 607 mDrmBuf[i] = NULL; 608 } 609 // reset VA variable 610 mVaDpy = 0; 611 mVaCfg = 0; 612 mVaCtx = 0; 613 mVaBufFilter = 0; 614 mSourceSurface = 0; 615 616 mWidth = 0; 617 mHeight = 0; 618 mRotatedWidth = 0; 619 mRotatedHeight = 0; 620 mRotatedStride = 0; 621 mTargetIndex = 0; 622 mBobDeinterlace = 0; 623 } 624 625 bool RotationBufferProvider::isContextChanged(int width, int height, int transform) 626 { 627 // check rotation config 628 if (height == mHeight && 629 width == mWidth && 630 transform == mTransform) { 631 return false; 632 } 633 634 return true; 635 } 636 637 } // name space intel 638 } // name space android 639