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     bool ret = false;
    384 
    385     if (payload->format != VA_FOURCC_NV12 || payload->width == 0 || payload->height == 0) {
    386         WLOGTRACE("payload data is not correct: format %#x, width %d, height %d",
    387             payload->format, payload->width, payload->height);
    388         return ret;
    389     }
    390 
    391     if (payload->width > 1280) {
    392         payload->tiling = 1;
    393     }
    394 
    395     do {
    396         if (isContextChanged(payload->width, payload->height, transform)) {
    397             DLOGTRACE("VA is restarted as rotation context changes");
    398 
    399             if (mVaInitialized) {
    400                 stopVA(); // need to re-initialize VA for new rotation config
    401             }
    402             mTransform = transform;
    403             mWidth = payload->width;
    404             mHeight = payload->height;
    405         }
    406 
    407         if (!mVaInitialized) {
    408             ret = startVA(payload, transform);
    409             if (ret == false) {
    410                 vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
    411                 break;
    412             }
    413         }
    414 
    415         // start to create next target surface
    416         if (!mRotatedSurfaces[mTargetIndex]) {
    417             ret = createVaSurface(payload, transform, true);
    418             if (ret == false) {
    419                 ELOGTRACE("failed to create target surface with attribute");
    420                 vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
    421                 break;
    422             }
    423         }
    424 
    425         // create source surface
    426         ret = createVaSurface(payload, transform, false);
    427         if (ret == false) {
    428             ELOGTRACE("failed to create source surface with attribute");
    429             vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
    430             break;
    431         }
    432 
    433 #ifdef DEBUG_ROTATION_PERFROMANCE
    434         uint32_t beginPicture = getMilliseconds();
    435 #endif
    436         vaStatus = vaBeginPicture(mVaDpy, mVaCtx, mRotatedSurfaces[mTargetIndex]);
    437         CHECK_VA_STATUS_BREAK("vaBeginPicture");
    438 
    439         VABufferID pipelineBuf;
    440         void *p;
    441         VAProcPipelineParameterBuffer *pipelineParam;
    442         vaStatus = vaCreateBuffer(mVaDpy,
    443                                   mVaCtx,
    444                                   VAProcPipelineParameterBufferType,
    445                                   sizeof(*pipelineParam),
    446                                   1,
    447                                   NULL,
    448                                   &pipelineBuf);
    449         CHECK_VA_STATUS_BREAK("vaCreateBuffer");
    450 
    451         vaStatus = vaMapBuffer(mVaDpy, pipelineBuf, &p);
    452         CHECK_VA_STATUS_BREAK("vaMapBuffer");
    453 
    454         pipelineParam = (VAProcPipelineParameterBuffer*)p;
    455         pipelineParam->surface = mSourceSurface;
    456         pipelineParam->rotation_state = transFromHalToVa(transform);
    457         pipelineParam->filters = &mVaBufFilter;
    458         pipelineParam->num_filters = 1;
    459         vaStatus = vaUnmapBuffer(mVaDpy, pipelineBuf);
    460         CHECK_VA_STATUS_BREAK("vaUnmapBuffer");
    461 
    462         vaStatus = vaRenderPicture(mVaDpy, mVaCtx, &pipelineBuf, 1);
    463         CHECK_VA_STATUS_BREAK("vaRenderPicture");
    464 
    465         vaStatus = vaEndPicture(mVaDpy, mVaCtx);
    466         CHECK_VA_STATUS_BREAK("vaEndPicture");
    467 
    468         vaStatus = vaSyncSurface(mVaDpy, mRotatedSurfaces[mTargetIndex]);
    469         CHECK_VA_STATUS_BREAK("vaSyncSurface");
    470 
    471 #ifdef DEBUG_ROTATION_PERFROMANCE
    472         ILOGTRACE("time spent %dms from vaBeginPicture to vaSyncSurface",
    473              getMilliseconds() - beginPicture);
    474 #endif
    475 
    476         // Populate payload fields so that overlayPlane can flip the buffer
    477         payload->rotated_width = mRotatedStride;
    478         payload->rotated_height = mRotatedHeight;
    479         payload->rotated_buffer_handle = mKhandles[mTargetIndex];
    480         // setting client transform to 0 to force re-generating rotated buffer whenever needed.
    481         payload->client_transform = 0;
    482         mTargetIndex++;
    483         if (mTargetIndex >= MAX_SURFACE_NUM)
    484             mTargetIndex = 0;
    485 
    486     } while (0);
    487 
    488 #ifdef DEBUG_ROTATION_PERFROMANCE
    489     ILOGTRACE("time spent %dms for setupRotationBuffer",
    490          getMilliseconds() - setup_Begin);
    491 #endif
    492 
    493     if (mSourceSurface > 0) {
    494         vaStatus = vaDestroySurfaces(mVaDpy, &mSourceSurface, 1);
    495         if (vaStatus != VA_STATUS_SUCCESS)
    496             WLOGTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
    497         mSourceSurface = 0;
    498     }
    499 
    500     if (vaStatus != VA_STATUS_SUCCESS) {
    501         stopVA();
    502         return false; // To not block HWC, just abort instead of retry
    503     }
    504 
    505     if (!payload->khandle) {
    506         WLOGTRACE("khandle is reset by decoder, surface is invalid!");
    507         return false;
    508     }
    509 
    510     return true;
    511 }
    512 
    513 bool RotationBufferProvider::prepareBufferInfo(int w, int h, int stride, VideoPayloadBuffer *payload, void *user_pt)
    514 {
    515     int size;
    516     void *buf = NULL;
    517 
    518     payload->width = payload->crop_width = w;
    519     payload->height = payload->crop_height = h;
    520     payload->format = VA_FOURCC_NV12;
    521     payload->tiling = 1;
    522     payload->luma_stride = stride;
    523     payload->chroma_u_stride = stride;
    524     payload->chroma_v_stride = stride;
    525     payload->client_transform = 0;
    526 
    527     size = stride * h + stride * h / 2;
    528 
    529     ssize_t index;
    530     index = mTTMWrappers.indexOfKey((uint64_t)user_pt);
    531     if (index < 0) {
    532         VLOGTRACE("wrapped userPt as wsbm buffer");
    533         bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt);
    534         if (ret == false) {
    535             ELOGTRACE("failed to allocate TTM buffer");
    536             return ret;
    537         }
    538 
    539         if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) {
    540             WLOGTRACE("mTTMWrappers is unexpectedly full. Invalidate caches");
    541             invalidateCaches();
    542         }
    543 
    544         index = mTTMWrappers.add((uint64_t)user_pt, buf);
    545     } else {
    546         VLOGTRACE("got wsbmBuffer in saved caches");
    547         buf = mTTMWrappers.valueAt(index);
    548     }
    549 
    550     payload->khandle = mWsbm->getKBufHandle(buf);
    551     return true;
    552 }
    553 
    554 void RotationBufferProvider::freeVaSurfaces()
    555 {
    556     bool ret;
    557     VAStatus vaStatus;
    558 
    559     for (int i = 0; i < MAX_SURFACE_NUM; i++) {
    560         if (NULL != mDrmBuf[i]) {
    561             ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]);
    562             if (!ret)
    563                 WLOGTRACE("failed to free TTMBuffer");
    564             mDrmBuf[i] = NULL;
    565         }
    566     }
    567 
    568     // remove wsbm buffer ref from VA
    569     for (int j = 0; j < MAX_SURFACE_NUM; j++) {
    570         if (0 != mRotatedSurfaces[j]) {
    571             vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1);
    572             if (vaStatus != VA_STATUS_SUCCESS)
    573                 WLOGTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
    574         }
    575         mRotatedSurfaces[j] = 0;
    576     }
    577 }
    578 
    579 void RotationBufferProvider::stopVA()
    580 {
    581     freeVaSurfaces();
    582 
    583     if (0 != mVaBufFilter)
    584         vaDestroyBuffer(mVaDpy, mVaBufFilter);
    585     if (0 != mVaCfg)
    586         vaDestroyConfig(mVaDpy,mVaCfg);
    587     if (0 != mVaCtx)
    588         vaDestroyContext(mVaDpy, mVaCtx);
    589     if (0 != mVaDpy)
    590         vaTerminate(mVaDpy);
    591 
    592     mVaInitialized = false;
    593 
    594     // reset VA variable
    595     mVaDpy = 0;
    596     mVaCfg = 0;
    597     mVaCtx = 0;
    598     mVaBufFilter = 0;
    599     mSourceSurface = 0;
    600 
    601     mWidth = 0;
    602     mHeight = 0;
    603     mRotatedWidth = 0;
    604     mRotatedHeight = 0;
    605     mRotatedStride = 0;
    606     mTargetIndex = 0;
    607 }
    608 
    609 bool RotationBufferProvider::isContextChanged(int width, int height, int transform)
    610 {
    611     // check rotation config
    612     if (height == mHeight &&
    613         width == mWidth &&
    614         transform == mTransform) {
    615         return false;
    616     }
    617 
    618     return true;
    619 }
    620 
    621 } // name space intel
    622 } // name space android
    623