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