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 
     20 namespace android {
     21 namespace intel {
     22 
     23 #define CHECK_VA_STATUS_RETURN(FUNC) \
     24 if (vaStatus != VA_STATUS_SUCCESS) {\
     25     ETRACE(FUNC" failed. vaStatus = %#x", vaStatus);\
     26     return false;\
     27 }
     28 
     29 #define CHECK_VA_STATUS_BREAK(FUNC) \
     30 if (vaStatus != VA_STATUS_SUCCESS) {\
     31     ETRACE(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             WTRACE("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 buffer_handle_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         ETRACE("failed to allocate TTM buffer");
    147         return 0;
    148     }
    149 
    150     return (buffer_handle_t) 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 + 0x1f) & ~0x1f;
    179         stride = payload->luma_stride; /* NV12 srouce buffer */
    180     }
    181 
    182     if (!stride) {
    183         ETRACE("invalid stride value");
    184         return false;
    185     }
    186 
    187     mBobDeinterlace = payload->bob_deinterlace;
    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         buffer_handle_t khandle = createWsbmBuffer(stride, bufferHeight, &mDrmBuf[mTargetIndex]);
    212         if (khandle == 0) {
    213             ETRACE("failed to create buffer by wsbm");
    214             return false;
    215         }
    216 
    217         mKhandles[mTargetIndex] = khandle;
    218         vaSurfaceAttrib->buffers[0] = (uintptr_t) khandle;
    219         mRotatedStride = stride;
    220         surface = &mRotatedSurfaces[mTargetIndex];
    221     } else {
    222         vaSurfaceAttrib->buffers[0] = (uintptr_t) 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             VTRACE("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         ETRACE("vaCreateSurfacesWithAttribute returns %d", vaStatus);
    244         ETRACE("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         ETRACE("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         ETRACE("numEntryPoints value is invalid");
    277         return false;
    278     }
    279 
    280     entryPoint = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * numEntryPoints);
    281     if (NULL == entryPoint) {
    282         ETRACE("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         ETRACE("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         ETRACE("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         ETRACE("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         ETRACE("VA_ROTATION_xxx: 0x%08x is not supported by the filter",
    368              transFromHalToVa(transform));
    369         return false;
    370     }
    371 
    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         WTRACE("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 && payload->width <= 2048) {
    393         payload->tiling = 1;
    394     }
    395 
    396     do {
    397         if (isContextChanged(payload->width, payload->height, transform)) {
    398             DTRACE("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                 ETRACE("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             ETRACE("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         pipelineParam->surface_region = NULL;
    461         pipelineParam->output_region = NULL;
    462         pipelineParam->num_forward_references = 0;
    463         pipelineParam->num_backward_references = 0;
    464         vaStatus = vaUnmapBuffer(mVaDpy, pipelineBuf);
    465         CHECK_VA_STATUS_BREAK("vaUnmapBuffer");
    466 
    467         vaStatus = vaRenderPicture(mVaDpy, mVaCtx, &pipelineBuf, 1);
    468         CHECK_VA_STATUS_BREAK("vaRenderPicture");
    469 
    470         vaStatus = vaEndPicture(mVaDpy, mVaCtx);
    471         CHECK_VA_STATUS_BREAK("vaEndPicture");
    472 
    473         vaStatus = vaSyncSurface(mVaDpy, mRotatedSurfaces[mTargetIndex]);
    474         CHECK_VA_STATUS_BREAK("vaSyncSurface");
    475 
    476 #ifdef DEBUG_ROTATION_PERFROMANCE
    477         ITRACE("time spent %dms from vaBeginPicture to vaSyncSurface",
    478              getMilliseconds() - beginPicture);
    479 #endif
    480 
    481         // Populate payload fields so that overlayPlane can flip the buffer
    482         payload->rotated_width = mRotatedStride;
    483         payload->rotated_height = mRotatedHeight;
    484         payload->rotated_buffer_handle = mKhandles[mTargetIndex];
    485         // setting client transform to 0 to force re-generating rotated buffer whenever needed.
    486         payload->client_transform = 0;
    487         mTargetIndex++;
    488         if (mTargetIndex >= MAX_SURFACE_NUM)
    489             mTargetIndex = 0;
    490 
    491     } while (0);
    492 
    493 #ifdef DEBUG_ROTATION_PERFROMANCE
    494     ITRACE("time spent %dms for setupRotationBuffer",
    495          getMilliseconds() - setup_Begin);
    496 #endif
    497 
    498     if (mSourceSurface > 0) {
    499         vaStatus = vaDestroySurfaces(mVaDpy, &mSourceSurface, 1);
    500         if (vaStatus != VA_STATUS_SUCCESS)
    501             WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
    502         mSourceSurface = 0;
    503     }
    504 
    505     if (vaStatus != VA_STATUS_SUCCESS) {
    506         stopVA();
    507         return false; // To not block HWC, just abort instead of retry
    508     }
    509 
    510     if (!payload->khandle) {
    511         WTRACE("khandle is reset by decoder, surface is invalid!");
    512         return false;
    513     }
    514 
    515     return true;
    516 }
    517 
    518 bool RotationBufferProvider::prepareBufferInfo(int w, int h, int stride, VideoPayloadBuffer *payload, void *user_pt)
    519 {
    520     int chroma_offset, size;
    521     void *buf = NULL;
    522 
    523     payload->width = payload->crop_width = w;
    524     payload->height = payload->crop_height = h;
    525     payload->coded_width = ((w + 0xf) & ~0xf);
    526     payload->coded_height = ((h + 0xf) & ~0xf);
    527     payload->format = VA_FOURCC_NV12;
    528     payload->tiling = 1;
    529     payload->luma_stride = stride;
    530     payload->chroma_u_stride = stride;
    531     payload->chroma_v_stride = stride;
    532     payload->client_transform = 0;
    533     payload->bob_deinterlace = 0;
    534 
    535     chroma_offset = stride * h;
    536     size = stride * h + stride * h / 2;
    537 
    538     ssize_t index;
    539     index = mTTMWrappers.indexOfKey((uint64_t)user_pt);
    540     if (index < 0) {
    541         VTRACE("wrapped userPt as wsbm buffer");
    542         bool ret = mWsbm->allocateTTMBufferUB(size, 0, &buf, user_pt);
    543         if (ret == false) {
    544             ETRACE("failed to allocate TTM buffer");
    545             return ret;
    546         }
    547 
    548         if (mTTMWrappers.size() >= TTM_WRAPPER_COUNT) {
    549             WTRACE("mTTMWrappers is unexpectedly full. Invalidate caches");
    550             invalidateCaches();
    551         }
    552 
    553         index = mTTMWrappers.add((uint64_t)user_pt, buf);
    554     } else {
    555         VTRACE("got wsbmBuffer in saved caches");
    556         buf = mTTMWrappers.valueAt(index);
    557     }
    558 
    559     payload->khandle = (buffer_handle_t) mWsbm->getKBufHandle(buf);
    560     return true;
    561 }
    562 
    563 void RotationBufferProvider::freeVaSurfaces()
    564 {
    565     bool ret;
    566     VAStatus vaStatus;
    567 
    568     for (int i = 0; i < MAX_SURFACE_NUM; i++) {
    569         if (NULL != mDrmBuf[i]) {
    570             ret = mWsbm->destroyTTMBuffer(mDrmBuf[i]);
    571             if (!ret)
    572                 WTRACE("failed to free TTMBuffer");
    573             mDrmBuf[i] = NULL;
    574         }
    575     }
    576 
    577     // remove wsbm buffer ref from VA
    578     for (int j = 0; j < MAX_SURFACE_NUM; j++) {
    579         if (0 != mRotatedSurfaces[j]) {
    580             vaStatus = vaDestroySurfaces(mVaDpy, &mRotatedSurfaces[j], 1);
    581             if (vaStatus != VA_STATUS_SUCCESS)
    582                 WTRACE("vaDestroySurfaces failed, vaStatus = %d", vaStatus);
    583         }
    584         mRotatedSurfaces[j] = 0;
    585     }
    586 }
    587 
    588 void RotationBufferProvider::stopVA()
    589 {
    590     freeVaSurfaces();
    591 
    592     if (0 != mVaBufFilter)
    593         vaDestroyBuffer(mVaDpy, mVaBufFilter);
    594     if (0 != mVaCfg)
    595         vaDestroyConfig(mVaDpy,mVaCfg);
    596     if (0 != mVaCtx)
    597         vaDestroyContext(mVaDpy, mVaCtx);
    598     if (0 != mVaDpy)
    599         vaTerminate(mVaDpy);
    600 
    601     mVaInitialized = false;
    602 
    603     for (int i = 0; i < MAX_SURFACE_NUM; i++) {
    604         mKhandles[i] = 0;
    605         mRotatedSurfaces[i] = 0;
    606         mDrmBuf[i] = NULL;
    607     }
    608     // reset VA variable
    609     mVaDpy = 0;
    610     mVaCfg = 0;
    611     mVaCtx = 0;
    612     mVaBufFilter = 0;
    613     mSourceSurface = 0;
    614 
    615     mWidth = 0;
    616     mHeight = 0;
    617     mRotatedWidth = 0;
    618     mRotatedHeight = 0;
    619     mRotatedStride = 0;
    620     mTargetIndex = 0;
    621     mBobDeinterlace = 0;
    622 }
    623 
    624 bool RotationBufferProvider::isContextChanged(int width, int height, int transform)
    625 {
    626     // check rotation config
    627     if (height == mHeight &&
    628         width == mWidth &&
    629         transform == mTransform) {
    630         return false;
    631     }
    632 
    633     return true;
    634 }
    635 
    636 } // name space intel
    637 } // name space android
    638