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 <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