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 #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     ELOGTRACE(FUNC" failed. vaStatus = %#x", vaStatus);\
     27     return false;\
     28 }
     29 
     30 #define CHECK_VA_STATUS_BREAK(FUNC) \
     31 if (vaStatus != VA_STATUS_SUCCESS) {\
     32     ELOGTRACE(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             WLOGTRACE("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 uint32_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         ELOGTRACE("failed to allocate TTM buffer");
    148         return 0;
    149     }
    150 
    151     return 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;
    180         stride = payload->luma_stride; /* NV12 srouce buffer */
    181     }
    182 
    183     if (!stride) {
    184         ELOGTRACE("invalid stride value");
    185         return false;
    186     }
    187 
    188     // adjust source target for Bob deinterlace
    189     if (!isTarget && mBobDeinterlace) {
    190         height >>= 1;
    191         bufferHeight >>= 1;
    192         stride <<= 1;
    193     }
    194 
    195     vaSurfaceAttrib->count = 1;
    196     vaSurfaceAttrib->width = width;
    197     vaSurfaceAttrib->height = height;
    198     vaSurfaceAttrib->pixel_format = payload->format;
    199     vaSurfaceAttrib->type = VAExternalMemoryKernelDRMBufffer;
    200     vaSurfaceAttrib->tiling = payload->tiling;
    201     vaSurfaceAttrib->size = (stride * bufferHeight * 3) / 2;
    202     vaSurfaceAttrib->luma_offset = 0;
    203     vaSurfaceAttrib->chroma_v_offset = stride * bufferHeight;
    204     vaSurfaceAttrib->luma_stride = vaSurfaceAttrib->chroma_u_stride
    205                                  = vaSurfaceAttrib->chroma_v_stride
    206                                  = stride;
    207     vaSurfaceAttrib->chroma_u_offset = vaSurfaceAttrib->chroma_v_offset;
    208     vaSurfaceAttrib->buffers = &buffers;
    209 
    210     if (isTarget) {
    211         int khandle = createWsbmBuffer(stride, bufferHeight, &mDrmBuf[mTargetIndex]);
    212         if (khandle == 0) {
    213             ELOGTRACE("failed to create buffer by wsbm");
    214             return false;
    215         }
    216 
    217         mKhandles[mTargetIndex] = khandle;
    218         vaSurfaceAttrib->buffers[0] = khandle;
    219         mRotatedStride = stride;
    220         surface = &mRotatedSurfaces[mTargetIndex];
    221     } else {
    222         vaSurfaceAttrib->buffers[0] = payload->khandle;
    223         surface = &mSourceSurface;
    224         /* set src surface width/height to video crop size */
    225         if (payload->crop_width && payload->crop_height) {
    226             width = payload->crop_width;
    227             height = (payload->crop_height >> mBobDeinterlace);
    228         } else {
    229             VLOGTRACE("Invalid cropping width or height");
    230             payload->crop_width = width;
    231             payload->crop_height = height;
    232         }
    233     }
    234 
    235     vaStatus = vaCreateSurfacesWithAttribute(mVaDpy,
    236                                              width,
    237                                              height,
    238                                              VA_RT_FORMAT_YUV420,
    239                                              1,
    240                                              surface,
    241                                              vaSurfaceAttrib);
    242     if (vaStatus != VA_STATUS_SUCCESS) {
    243         ELOGTRACE("vaCreateSurfacesWithAttribute returns %d", vaStatus);
    244         ELOGTRACE("Attributes: target: %d, width: %d, height %d, bufferHeight %d, tiling %d",
    245                 isTarget, width, height, bufferHeight, payload->tiling);
    246         *surface = 0;
    247         return false;
    248     }
    249 
    250     return true;
    251 }
    252 
    253 bool RotationBufferProvider::startVA(VideoPayloadBuffer *payload, int transform)
    254 {
    255     bool ret = true;
    256     VAStatus vaStatus;
    257     VAEntrypoint *entryPoint;
    258     VAConfigAttrib attribDummy;
    259     int numEntryPoints;
    260     bool supportVideoProcessing = false;
    261     int majorVer = 0, minorVer = 0;
    262 
    263     // VA will hold a copy of the param pointer, so local varialbe doesn't work
    264     mVaDpy = vaGetDisplay(&mDisplay);
    265     if (NULL == mVaDpy) {
    266         ELOGTRACE("failed to get VADisplay");
    267         return false;
    268     }
    269 
    270     vaStatus = vaInitialize(mVaDpy, &majorVer, &minorVer);
    271     CHECK_VA_STATUS_RETURN("vaInitialize");
    272 
    273     numEntryPoints = vaMaxNumEntrypoints(mVaDpy);
    274 
    275     if (numEntryPoints <= 0) {
    276         ELOGTRACE("numEntryPoints value is invalid");
    277         return false;
    278     }
    279 
    280     entryPoint = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * numEntryPoints);
    281     if (NULL == entryPoint) {
    282         ELOGTRACE("failed to malloc memory for entryPoint");
    283         return false;
    284     }
    285 
    286     vaStatus = vaQueryConfigEntrypoints(mVaDpy,
    287                                         VAProfileNone,
    288                                         entryPoint,
    289                                         &numEntryPoints);
    290     CHECK_VA_STATUS_RETURN("vaQueryConfigEntrypoints");
    291 
    292     for (int i = 0; i < numEntryPoints; i++)
    293         if (entryPoint[i] == VAEntrypointVideoProc)
    294             supportVideoProcessing = true;
    295 
    296     free(entryPoint);
    297     entryPoint = NULL;
    298 
    299     if (!supportVideoProcessing) {
    300         ELOGTRACE("VAEntrypointVideoProc is not supported");
    301         return false;
    302     }
    303 
    304     vaStatus = vaCreateConfig(mVaDpy,
    305                               VAProfileNone,
    306                               VAEntrypointVideoProc,
    307                               &attribDummy,
    308                               0,
    309                               &mVaCfg);
    310     CHECK_VA_STATUS_RETURN("vaCreateConfig");
    311 
    312     // create first target surface
    313     ret = createVaSurface(payload, transform, true);
    314     if (ret == false) {
    315         ELOGTRACE("failed to create target surface with attribute");
    316         return false;
    317     }
    318 
    319     vaStatus = vaCreateContext(mVaDpy,
    320                                mVaCfg,
    321                                payload->width,
    322                                payload->height,
    323                                0,
    324                                &mRotatedSurfaces[0],
    325                                1,
    326                                &mVaCtx);
    327     CHECK_VA_STATUS_RETURN("vaCreateContext");
    328 
    329     VAProcFilterType filters[VAProcFilterCount];
    330     unsigned int numFilters = VAProcFilterCount;
    331     vaStatus = vaQueryVideoProcFilters(mVaDpy, mVaCtx, filters, &numFilters);
    332     CHECK_VA_STATUS_RETURN("vaQueryVideoProcFilters");
    333 
    334     bool supportVideoProcFilter = false;
    335     for (unsigned int j = 0; j < numFilters; j++)
    336         if (filters[j] == VAProcFilterNone)
    337             supportVideoProcFilter = true;
    338 
    339     if (!supportVideoProcFilter) {
    340         ELOGTRACE("VAProcFilterNone is not supported");
    341         return false;
    342     }
    343 
    344     VAProcFilterParameterBuffer filter;
    345     filter.type = VAProcFilterNone;
    346     filter.value = 0;
    347 
    348     vaStatus = vaCreateBuffer(mVaDpy,
    349                               mVaCtx,
    350                               VAProcFilterParameterBufferType,
    351                               sizeof(filter),
    352                               1,
    353                               &filter,
    354                               &mVaBufFilter);
    355     CHECK_VA_STATUS_RETURN("vaCreateBuffer");
    356 
    357     VAProcPipelineCaps pipelineCaps;
    358     unsigned int numCaps = 1;
    359     vaStatus = vaQueryVideoProcPipelineCaps(mVaDpy,
    360                                             mVaCtx,
    361                                             &mVaBufFilter,
    362                                             numCaps,
    363                                             &pipelineCaps);
    364     CHECK_VA_STATUS_RETURN("vaQueryVideoProcPipelineCaps");
    365 
    366     if (!(pipelineCaps.rotation_flags & (1 << transFromHalToVa(transform)))) {
    367         ELOGTRACE("VA_ROTATION_xxx: 0x%08x is not supported by the filter",
    368              transFromHalToVa(transform));
    369         return false;
    370     }
    371 
    372     mBobDeinterlace = payload->bob_deinterlace;
    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     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 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     size = stride * h + stride * h / 2;
    529 
    530     ssize_t index;
    531     index = mTTMWrappers.indexOfKey((uint64_t)user_pt);
    532     if (index < 0) {
    533         VLOGTRACE("wrapped userPt as wsbm buffer");
    534         bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt);
    535         if (ret == false) {
    536             ELOGTRACE("failed to allocate TTM buffer");
    537             return ret;
    538         }
    539 
    540         if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) {
    541             WLOGTRACE("mTTMWrappers is unexpectedly full. Invalidate caches");
    542             invalidateCaches();
    543         }
    544 
    545         index = mTTMWrappers.add((uint64_t)user_pt, buf);
    546     } else {
    547         VLOGTRACE("got wsbmBuffer in saved caches");
    548         buf = mTTMWrappers.valueAt(index);
    549     }
    550 
    551     payload->khandle = mWsbm->getKBufHandle(buf);
    552     return true;
    553 }
    554 
    555 void RotationBufferProvider::freeVaSurfaces()
    556 {
    557     bool ret;
    558     VAStatus vaStatus;
    559 
    560     for (int i = 0; i < MAX_SURFACE_NUM; i++) {
    561         if (NULL != mDrmBuf[i]) {
    562             ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]);
    563             if (!ret)
    564                 WLOGTRACE("failed to free TTMBuffer");
    565             mDrmBuf[i] = NULL;
    566         }
    567     }
    568 
    569     // remove wsbm buffer ref from VA
    570     for (int j = 0; j < MAX_SURFACE_NUM; j++) {
    571         if (0 != mRotatedSurfaces[j]) {
    572             vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1);
    573             if (vaStatus != VA_STATUS_SUCCESS)
    574                 WLOGTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
    575         }
    576         mRotatedSurfaces[j] = 0;
    577     }
    578 }
    579 
    580 void RotationBufferProvider::stopVA()
    581 {
    582     freeVaSurfaces();
    583 
    584     if (0 != mVaBufFilter)
    585         vaDestroyBuffer(mVaDpy, mVaBufFilter);
    586     if (0 != mVaCfg)
    587         vaDestroyConfig(mVaDpy,mVaCfg);
    588     if (0 != mVaCtx)
    589         vaDestroyContext(mVaDpy, mVaCtx);
    590     if (0 != mVaDpy)
    591         vaTerminate(mVaDpy);
    592 
    593     mVaInitialized = false;
    594 
    595     // reset VA variable
    596     mVaDpy = 0;
    597     mVaCfg = 0;
    598     mVaCtx = 0;
    599     mVaBufFilter = 0;
    600     mSourceSurface = 0;
    601 
    602     mWidth = 0;
    603     mHeight = 0;
    604     mRotatedWidth = 0;
    605     mRotatedHeight = 0;
    606     mRotatedStride = 0;
    607     mTargetIndex = 0;
    608 }
    609 
    610 bool RotationBufferProvider::isContextChanged(int width, int height, int transform)
    611 {
    612     // check rotation config
    613     if (height == mHeight &&
    614         width == mWidth &&
    615         transform == mTransform) {
    616         return false;
    617     }
    618 
    619     return true;
    620 }
    621 
    622 } // name space intel
    623 } // name space android
    624