Home | History | Annotate | Download | only in gui
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "GLConsumer"
     18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     19 //#define LOG_NDEBUG 0
     20 
     21 #define GL_GLEXT_PROTOTYPES
     22 #define EGL_EGLEXT_PROTOTYPES
     23 
     24 #include <EGL/egl.h>
     25 #include <EGL/eglext.h>
     26 #include <GLES2/gl2.h>
     27 #include <GLES2/gl2ext.h>
     28 #include <cutils/compiler.h>
     29 
     30 #include <hardware/hardware.h>
     31 
     32 #include <gui/GLConsumer.h>
     33 #include <gui/IGraphicBufferAlloc.h>
     34 #include <gui/ISurfaceComposer.h>
     35 #include <gui/SurfaceComposerClient.h>
     36 
     37 #include <private/gui/ComposerService.h>
     38 #include <private/gui/SyncFeatures.h>
     39 
     40 #include <utils/Log.h>
     41 #include <utils/String8.h>
     42 #include <utils/Trace.h>
     43 
     44 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
     45 #define CROP_EXT_STR "EGL_ANDROID_image_crop"
     46 
     47 namespace android {
     48 
     49 // Macros for including the GLConsumer name in log messages
     50 #define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
     51 #define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
     52 #define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
     53 #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
     54 #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
     55 
     56 static const struct {
     57     size_t width, height;
     58     char const* bits;
     59 } kDebugData = { 15, 12,
     60     "___________________________________XX_XX_______X_X_____X_X____X_XXXXXXX_X____XXXXXXXXXXX__"
     61     "___XX_XXX_XX_______XXXXXXX_________X___X_________X_____X__________________________________"
     62 };
     63 
     64 // Transform matrices
     65 static float mtxIdentity[16] = {
     66     1, 0, 0, 0,
     67     0, 1, 0, 0,
     68     0, 0, 1, 0,
     69     0, 0, 0, 1,
     70 };
     71 static float mtxFlipH[16] = {
     72     -1, 0, 0, 0,
     73     0, 1, 0, 0,
     74     0, 0, 1, 0,
     75     1, 0, 0, 1,
     76 };
     77 static float mtxFlipV[16] = {
     78     1, 0, 0, 0,
     79     0, -1, 0, 0,
     80     0, 0, 1, 0,
     81     0, 1, 0, 1,
     82 };
     83 static float mtxRot90[16] = {
     84     0, 1, 0, 0,
     85     -1, 0, 0, 0,
     86     0, 0, 1, 0,
     87     1, 0, 0, 1,
     88 };
     89 
     90 static void mtxMul(float out[16], const float a[16], const float b[16]);
     91 
     92 Mutex GLConsumer::sStaticInitLock;
     93 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
     94 
     95 static bool hasEglAndroidImageCropImpl() {
     96     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     97     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
     98     size_t cropExtLen = strlen(CROP_EXT_STR);
     99     size_t extsLen = strlen(exts);
    100     bool equal = !strcmp(CROP_EXT_STR, exts);
    101     bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
    102     bool atEnd = (cropExtLen+1) < extsLen &&
    103             !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
    104     bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
    105     return equal || atStart || atEnd || inMiddle;
    106 }
    107 
    108 static bool hasEglAndroidImageCrop() {
    109     // Only compute whether the extension is present once the first time this
    110     // function is called.
    111     static bool hasIt = hasEglAndroidImageCropImpl();
    112     return hasIt;
    113 }
    114 
    115 static bool isEglImageCroppable(const Rect& crop) {
    116     return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
    117 }
    118 
    119 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
    120         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
    121     ConsumerBase(bq, isControlledByApp),
    122     mCurrentTransform(0),
    123     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
    124     mCurrentFence(Fence::NO_FENCE),
    125     mCurrentTimestamp(0),
    126     mCurrentFrameNumber(0),
    127     mDefaultWidth(1),
    128     mDefaultHeight(1),
    129     mFilteringEnabled(true),
    130     mTexName(tex),
    131     mUseFenceSync(useFenceSync),
    132     mTexTarget(texTarget),
    133     mEglDisplay(EGL_NO_DISPLAY),
    134     mEglContext(EGL_NO_CONTEXT),
    135     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    136     mAttached(true)
    137 {
    138     ST_LOGV("GLConsumer");
    139 
    140     memcpy(mCurrentTransformMatrix, mtxIdentity,
    141             sizeof(mCurrentTransformMatrix));
    142 
    143     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
    144 }
    145 
    146 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
    147         bool useFenceSync, bool isControlledByApp) :
    148     ConsumerBase(bq, isControlledByApp),
    149     mCurrentTransform(0),
    150     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
    151     mCurrentFence(Fence::NO_FENCE),
    152     mCurrentTimestamp(0),
    153     mCurrentFrameNumber(0),
    154     mDefaultWidth(1),
    155     mDefaultHeight(1),
    156     mFilteringEnabled(true),
    157     mTexName(-1),
    158     mUseFenceSync(useFenceSync),
    159     mTexTarget(texTarget),
    160     mEglDisplay(EGL_NO_DISPLAY),
    161     mEglContext(EGL_NO_CONTEXT),
    162     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
    163     mAttached(false)
    164 {
    165     ST_LOGV("GLConsumer");
    166 
    167     memcpy(mCurrentTransformMatrix, mtxIdentity,
    168             sizeof(mCurrentTransformMatrix));
    169 
    170     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
    171 }
    172 
    173 status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
    174     Mutex::Autolock lock(mMutex);
    175     return mConsumer->setDefaultMaxBufferCount(bufferCount);
    176 }
    177 
    178 
    179 status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
    180 {
    181     Mutex::Autolock lock(mMutex);
    182     mDefaultWidth = w;
    183     mDefaultHeight = h;
    184     return mConsumer->setDefaultBufferSize(w, h);
    185 }
    186 
    187 status_t GLConsumer::updateTexImage() {
    188     ATRACE_CALL();
    189     ST_LOGV("updateTexImage");
    190     Mutex::Autolock lock(mMutex);
    191 
    192     if (mAbandoned) {
    193         ST_LOGE("updateTexImage: GLConsumer is abandoned!");
    194         return NO_INIT;
    195     }
    196 
    197     // Make sure the EGL state is the same as in previous calls.
    198     status_t err = checkAndUpdateEglStateLocked();
    199     if (err != NO_ERROR) {
    200         return err;
    201     }
    202 
    203     BufferQueue::BufferItem item;
    204 
    205     // Acquire the next buffer.
    206     // In asynchronous mode the list is guaranteed to be one buffer
    207     // deep, while in synchronous mode we use the oldest buffer.
    208     err = acquireBufferLocked(&item, 0);
    209     if (err != NO_ERROR) {
    210         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
    211             // We always bind the texture even if we don't update its contents.
    212             ST_LOGV("updateTexImage: no buffers were available");
    213             glBindTexture(mTexTarget, mTexName);
    214             err = NO_ERROR;
    215         } else {
    216             ST_LOGE("updateTexImage: acquire failed: %s (%d)",
    217                 strerror(-err), err);
    218         }
    219         return err;
    220     }
    221 
    222     // Release the previous buffer.
    223     err = updateAndReleaseLocked(item);
    224     if (err != NO_ERROR) {
    225         // We always bind the texture.
    226         glBindTexture(mTexTarget, mTexName);
    227         return err;
    228     }
    229 
    230     // Bind the new buffer to the GL texture, and wait until it's ready.
    231     return bindTextureImageLocked();
    232 }
    233 
    234 
    235 status_t GLConsumer::releaseTexImage() {
    236     ATRACE_CALL();
    237     ST_LOGV("releaseTexImage");
    238     Mutex::Autolock lock(mMutex);
    239 
    240     if (mAbandoned) {
    241         ST_LOGE("releaseTexImage: GLConsumer is abandoned!");
    242         return NO_INIT;
    243     }
    244 
    245     // Make sure the EGL state is the same as in previous calls.
    246     status_t err = NO_ERROR;
    247 
    248     if (mAttached) {
    249         err = checkAndUpdateEglStateLocked(true);
    250         if (err != NO_ERROR) {
    251             return err;
    252         }
    253     } else {
    254         // if we're detached, no need to validate EGL's state -- we won't use it.
    255     }
    256 
    257     // Update the GLConsumer state.
    258     int buf = mCurrentTexture;
    259     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
    260 
    261         ST_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached);
    262 
    263         if (mAttached) {
    264             // Do whatever sync ops we need to do before releasing the slot.
    265             err = syncForReleaseLocked(mEglDisplay);
    266             if (err != NO_ERROR) {
    267                 ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
    268                 return err;
    269             }
    270         } else {
    271             // if we're detached, we just use the fence that was created in detachFromContext()
    272             // so... basically, nothing more to do here.
    273         }
    274 
    275         err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
    276         if (err < NO_ERROR) {
    277             ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)",
    278                     strerror(-err), err);
    279             return err;
    280         }
    281 
    282         if (mReleasedTexImage == NULL) {
    283             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
    284         }
    285 
    286         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
    287         mCurrentTextureImage = mReleasedTexImage;
    288         mCurrentCrop.makeInvalid();
    289         mCurrentTransform = 0;
    290         mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
    291         mCurrentTimestamp = 0;
    292         mCurrentFence = Fence::NO_FENCE;
    293 
    294         if (mAttached) {
    295             // This binds a dummy buffer (mReleasedTexImage).
    296             status_t err =  bindTextureImageLocked();
    297             if (err != NO_ERROR) {
    298                 return err;
    299             }
    300         } else {
    301             // detached, don't touch the texture (and we may not even have an
    302             // EGLDisplay here.
    303         }
    304     }
    305 
    306     return NO_ERROR;
    307 }
    308 
    309 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
    310     Mutex::Autolock _l(sStaticInitLock);
    311     if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
    312         // The first time, create the debug texture in case the application
    313         // continues to use it.
    314         sp<GraphicBuffer> buffer = new GraphicBuffer(
    315                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
    316                 GraphicBuffer::USAGE_SW_WRITE_RARELY);
    317         uint32_t* bits;
    318         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
    319         size_t w = buffer->getStride();
    320         size_t h = buffer->getHeight();
    321         memset(bits, 0, w*h*4);
    322         for (size_t y=0 ; y<kDebugData.height ; y++) {
    323             for (size_t x=0 ; x<kDebugData.width ; x++) {
    324                 bits[x] = (kDebugData.bits[y*kDebugData.width+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF;
    325             }
    326             bits += w;
    327         }
    328         buffer->unlock();
    329         sReleasedTexImageBuffer = buffer;
    330     }
    331     return sReleasedTexImageBuffer;
    332 }
    333 
    334 status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
    335         nsecs_t presentWhen) {
    336     status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
    337     if (err != NO_ERROR) {
    338         return err;
    339     }
    340 
    341     // If item->mGraphicBuffer is not null, this buffer has not been acquired
    342     // before, so any prior EglImage created is using a stale buffer. This
    343     // replaces any old EglImage with a new one (using the new buffer).
    344     if (item->mGraphicBuffer != NULL) {
    345         int slot = item->mBuf;
    346         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
    347     }
    348 
    349     return NO_ERROR;
    350 }
    351 
    352 status_t GLConsumer::releaseBufferLocked(int buf,
    353         sp<GraphicBuffer> graphicBuffer,
    354         EGLDisplay display, EGLSyncKHR eglFence) {
    355     // release the buffer if it hasn't already been discarded by the
    356     // BufferQueue. This can happen, for example, when the producer of this
    357     // buffer has reallocated the original buffer slot after this buffer
    358     // was acquired.
    359     status_t err = ConsumerBase::releaseBufferLocked(
    360             buf, graphicBuffer, display, eglFence);
    361     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
    362     return err;
    363 }
    364 
    365 status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
    366 {
    367     status_t err = NO_ERROR;
    368 
    369     int buf = item.mBuf;
    370 
    371     if (!mAttached) {
    372         ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
    373                 "ES context");
    374         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
    375                 mEglDisplay, EGL_NO_SYNC_KHR);
    376         return INVALID_OPERATION;
    377     }
    378 
    379     // Confirm state.
    380     err = checkAndUpdateEglStateLocked();
    381     if (err != NO_ERROR) {
    382         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
    383                 mEglDisplay, EGL_NO_SYNC_KHR);
    384         return err;
    385     }
    386 
    387     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
    388     // if nessessary, for the gralloc buffer currently in the slot in
    389     // ConsumerBase.
    390     // We may have to do this even when item.mGraphicBuffer == NULL (which
    391     // means the buffer was previously acquired).
    392     err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
    393     if (err != NO_ERROR) {
    394         ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
    395                 mEglDisplay, buf);
    396         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
    397                 mEglDisplay, EGL_NO_SYNC_KHR);
    398         return UNKNOWN_ERROR;
    399     }
    400 
    401     // Do whatever sync ops we need to do before releasing the old slot.
    402     err = syncForReleaseLocked(mEglDisplay);
    403     if (err != NO_ERROR) {
    404         // Release the buffer we just acquired.  It's not safe to
    405         // release the old buffer, so instead we just drop the new frame.
    406         // As we are still under lock since acquireBuffer, it is safe to
    407         // release by slot.
    408         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
    409                 mEglDisplay, EGL_NO_SYNC_KHR);
    410         return err;
    411     }
    412 
    413     ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
    414             mCurrentTexture, mCurrentTextureImage != NULL ?
    415                     mCurrentTextureImage->graphicBufferHandle() : 0,
    416             buf, mSlots[buf].mGraphicBuffer->handle);
    417 
    418     // release old buffer
    419     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    420         status_t status = releaseBufferLocked(
    421                 mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
    422                 mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
    423         if (status < NO_ERROR) {
    424             ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
    425                    strerror(-status), status);
    426             err = status;
    427             // keep going, with error raised [?]
    428         }
    429     }
    430 
    431     // Update the GLConsumer state.
    432     mCurrentTexture = buf;
    433     mCurrentTextureImage = mEglSlots[buf].mEglImage;
    434     mCurrentCrop = item.mCrop;
    435     mCurrentTransform = item.mTransform;
    436     mCurrentScalingMode = item.mScalingMode;
    437     mCurrentTimestamp = item.mTimestamp;
    438     mCurrentFence = item.mFence;
    439     mCurrentFrameNumber = item.mFrameNumber;
    440 
    441     computeCurrentTransformMatrixLocked();
    442 
    443     return err;
    444 }
    445 
    446 status_t GLConsumer::bindTextureImageLocked() {
    447     if (mEglDisplay == EGL_NO_DISPLAY) {
    448         ALOGE("bindTextureImage: invalid display");
    449         return INVALID_OPERATION;
    450     }
    451 
    452     GLint error;
    453     while ((error = glGetError()) != GL_NO_ERROR) {
    454         ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
    455     }
    456 
    457     glBindTexture(mTexTarget, mTexName);
    458     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
    459             mCurrentTextureImage == NULL) {
    460         ST_LOGE("bindTextureImage: no currently-bound texture");
    461         return NO_INIT;
    462     }
    463 
    464     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
    465                                                         mCurrentCrop);
    466     if (err != NO_ERROR) {
    467         ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
    468                 mEglDisplay, mCurrentTexture);
    469         return UNKNOWN_ERROR;
    470     }
    471     mCurrentTextureImage->bindToTextureTarget(mTexTarget);
    472 
    473     // In the rare case that the display is terminated and then initialized
    474     // again, we can't detect that the display changed (it didn't), but the
    475     // image is invalid. In this case, repeat the exact same steps while
    476     // forcing the creation of a new image.
    477     if ((error = glGetError()) != GL_NO_ERROR) {
    478         glBindTexture(mTexTarget, mTexName);
    479         status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
    480                                                             mCurrentCrop,
    481                                                             true);
    482         if (err != NO_ERROR) {
    483             ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
    484                     mEglDisplay, mCurrentTexture);
    485             return UNKNOWN_ERROR;
    486         }
    487         mCurrentTextureImage->bindToTextureTarget(mTexTarget);
    488         if ((error = glGetError()) != GL_NO_ERROR) {
    489             ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
    490             return UNKNOWN_ERROR;
    491         }
    492     }
    493 
    494     // Wait for the new buffer to be ready.
    495     return doGLFenceWaitLocked();
    496 }
    497 
    498 status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
    499     EGLDisplay dpy = eglGetCurrentDisplay();
    500     EGLContext ctx = eglGetCurrentContext();
    501 
    502     if (!contextCheck) {
    503         // if this is the first time we're called, mEglDisplay/mEglContext have
    504         // never been set, so don't error out (below).
    505         if (mEglDisplay == EGL_NO_DISPLAY) {
    506             mEglDisplay = dpy;
    507         }
    508         if (mEglContext == EGL_NO_DISPLAY) {
    509             mEglContext = ctx;
    510         }
    511     }
    512 
    513     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
    514         ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
    515         return INVALID_OPERATION;
    516     }
    517 
    518     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
    519         ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
    520         return INVALID_OPERATION;
    521     }
    522 
    523     mEglDisplay = dpy;
    524     mEglContext = ctx;
    525     return NO_ERROR;
    526 }
    527 
    528 void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
    529     if (fence->isValid() &&
    530             mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    531         status_t err = addReleaseFence(mCurrentTexture,
    532                 mCurrentTextureImage->graphicBuffer(), fence);
    533         if (err != OK) {
    534             ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
    535                     strerror(-err), err);
    536         }
    537     }
    538 }
    539 
    540 status_t GLConsumer::detachFromContext() {
    541     ATRACE_CALL();
    542     ST_LOGV("detachFromContext");
    543     Mutex::Autolock lock(mMutex);
    544 
    545     if (mAbandoned) {
    546         ST_LOGE("detachFromContext: abandoned GLConsumer");
    547         return NO_INIT;
    548     }
    549 
    550     if (!mAttached) {
    551         ST_LOGE("detachFromContext: GLConsumer is not attached to a "
    552                 "context");
    553         return INVALID_OPERATION;
    554     }
    555 
    556     EGLDisplay dpy = eglGetCurrentDisplay();
    557     EGLContext ctx = eglGetCurrentContext();
    558 
    559     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
    560         ST_LOGE("detachFromContext: invalid current EGLDisplay");
    561         return INVALID_OPERATION;
    562     }
    563 
    564     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
    565         ST_LOGE("detachFromContext: invalid current EGLContext");
    566         return INVALID_OPERATION;
    567     }
    568 
    569     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
    570         status_t err = syncForReleaseLocked(dpy);
    571         if (err != OK) {
    572             return err;
    573         }
    574 
    575         glDeleteTextures(1, &mTexName);
    576     }
    577 
    578     mEglDisplay = EGL_NO_DISPLAY;
    579     mEglContext = EGL_NO_CONTEXT;
    580     mAttached = false;
    581 
    582     return OK;
    583 }
    584 
    585 status_t GLConsumer::attachToContext(uint32_t tex) {
    586     ATRACE_CALL();
    587     ST_LOGV("attachToContext");
    588     Mutex::Autolock lock(mMutex);
    589 
    590     if (mAbandoned) {
    591         ST_LOGE("attachToContext: abandoned GLConsumer");
    592         return NO_INIT;
    593     }
    594 
    595     if (mAttached) {
    596         ST_LOGE("attachToContext: GLConsumer is already attached to a "
    597                 "context");
    598         return INVALID_OPERATION;
    599     }
    600 
    601     EGLDisplay dpy = eglGetCurrentDisplay();
    602     EGLContext ctx = eglGetCurrentContext();
    603 
    604     if (dpy == EGL_NO_DISPLAY) {
    605         ST_LOGE("attachToContext: invalid current EGLDisplay");
    606         return INVALID_OPERATION;
    607     }
    608 
    609     if (ctx == EGL_NO_CONTEXT) {
    610         ST_LOGE("attachToContext: invalid current EGLContext");
    611         return INVALID_OPERATION;
    612     }
    613 
    614     // We need to bind the texture regardless of whether there's a current
    615     // buffer.
    616     glBindTexture(mTexTarget, GLuint(tex));
    617 
    618     mEglDisplay = dpy;
    619     mEglContext = ctx;
    620     mTexName = tex;
    621     mAttached = true;
    622 
    623     if (mCurrentTextureImage != NULL) {
    624         // This may wait for a buffer a second time. This is likely required if
    625         // this is a different context, since otherwise the wait could be skipped
    626         // by bouncing through another context. For the same context the extra
    627         // wait is redundant.
    628         status_t err =  bindTextureImageLocked();
    629         if (err != NO_ERROR) {
    630             return err;
    631         }
    632     }
    633 
    634     return OK;
    635 }
    636 
    637 
    638 status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
    639     ST_LOGV("syncForReleaseLocked");
    640 
    641     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    642         if (SyncFeatures::getInstance().useNativeFenceSync()) {
    643             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
    644                     EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
    645             if (sync == EGL_NO_SYNC_KHR) {
    646                 ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
    647                         eglGetError());
    648                 return UNKNOWN_ERROR;
    649             }
    650             glFlush();
    651             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
    652             eglDestroySyncKHR(dpy, sync);
    653             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
    654                 ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
    655                         "fd: %#x", eglGetError());
    656                 return UNKNOWN_ERROR;
    657             }
    658             sp<Fence> fence(new Fence(fenceFd));
    659             status_t err = addReleaseFenceLocked(mCurrentTexture,
    660                     mCurrentTextureImage->graphicBuffer(), fence);
    661             if (err != OK) {
    662                 ST_LOGE("syncForReleaseLocked: error adding release fence: "
    663                         "%s (%d)", strerror(-err), err);
    664                 return err;
    665             }
    666         } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
    667             EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
    668             if (fence != EGL_NO_SYNC_KHR) {
    669                 // There is already a fence for the current slot.  We need to
    670                 // wait on that before replacing it with another fence to
    671                 // ensure that all outstanding buffer accesses have completed
    672                 // before the producer accesses it.
    673                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
    674                 if (result == EGL_FALSE) {
    675                     ST_LOGE("syncForReleaseLocked: error waiting for previous "
    676                             "fence: %#x", eglGetError());
    677                     return UNKNOWN_ERROR;
    678                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
    679                     ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
    680                             "fence");
    681                     return TIMED_OUT;
    682                 }
    683                 eglDestroySyncKHR(dpy, fence);
    684             }
    685 
    686             // Create a fence for the outstanding accesses in the current
    687             // OpenGL ES context.
    688             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
    689             if (fence == EGL_NO_SYNC_KHR) {
    690                 ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
    691                         eglGetError());
    692                 return UNKNOWN_ERROR;
    693             }
    694             glFlush();
    695             mEglSlots[mCurrentTexture].mEglFence = fence;
    696         }
    697     }
    698 
    699     return OK;
    700 }
    701 
    702 bool GLConsumer::isExternalFormat(uint32_t format)
    703 {
    704     switch (format) {
    705     // supported YUV formats
    706     case HAL_PIXEL_FORMAT_YV12:
    707     // Legacy/deprecated YUV formats
    708     case HAL_PIXEL_FORMAT_YCbCr_422_SP:
    709     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    710     case HAL_PIXEL_FORMAT_YCbCr_422_I:
    711         return true;
    712     }
    713 
    714     // Any OEM format needs to be considered
    715     if (format>=0x100 && format<=0x1FF)
    716         return true;
    717 
    718     return false;
    719 }
    720 
    721 uint32_t GLConsumer::getCurrentTextureTarget() const {
    722     return mTexTarget;
    723 }
    724 
    725 void GLConsumer::getTransformMatrix(float mtx[16]) {
    726     Mutex::Autolock lock(mMutex);
    727     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
    728 }
    729 
    730 void GLConsumer::setFilteringEnabled(bool enabled) {
    731     Mutex::Autolock lock(mMutex);
    732     if (mAbandoned) {
    733         ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
    734         return;
    735     }
    736     bool needsRecompute = mFilteringEnabled != enabled;
    737     mFilteringEnabled = enabled;
    738 
    739     if (needsRecompute && mCurrentTextureImage==NULL) {
    740         ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
    741     }
    742 
    743     if (needsRecompute && mCurrentTextureImage != NULL) {
    744         computeCurrentTransformMatrixLocked();
    745     }
    746 }
    747 
    748 void GLConsumer::computeCurrentTransformMatrixLocked() {
    749     ST_LOGV("computeCurrentTransformMatrixLocked");
    750 
    751     float xform[16];
    752     for (int i = 0; i < 16; i++) {
    753         xform[i] = mtxIdentity[i];
    754     }
    755     if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
    756         float result[16];
    757         mtxMul(result, xform, mtxFlipH);
    758         for (int i = 0; i < 16; i++) {
    759             xform[i] = result[i];
    760         }
    761     }
    762     if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
    763         float result[16];
    764         mtxMul(result, xform, mtxFlipV);
    765         for (int i = 0; i < 16; i++) {
    766             xform[i] = result[i];
    767         }
    768     }
    769     if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
    770         float result[16];
    771         mtxMul(result, xform, mtxRot90);
    772         for (int i = 0; i < 16; i++) {
    773             xform[i] = result[i];
    774         }
    775     }
    776 
    777     sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
    778             NULL : mCurrentTextureImage->graphicBuffer();
    779 
    780     if (buf == NULL) {
    781         ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
    782     }
    783 
    784     float mtxBeforeFlipV[16];
    785     if (!isEglImageCroppable(mCurrentCrop)) {
    786         Rect cropRect = mCurrentCrop;
    787         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
    788         float bufferWidth = buf->getWidth();
    789         float bufferHeight = buf->getHeight();
    790         if (!cropRect.isEmpty()) {
    791             float shrinkAmount = 0.0f;
    792             if (mFilteringEnabled) {
    793                 // In order to prevent bilinear sampling beyond the edge of the
    794                 // crop rectangle we may need to shrink it by 2 texels in each
    795                 // dimension.  Normally this would just need to take 1/2 a texel
    796                 // off each end, but because the chroma channels of YUV420 images
    797                 // are subsampled we may need to shrink the crop region by a whole
    798                 // texel on each side.
    799                 switch (buf->getPixelFormat()) {
    800                     case PIXEL_FORMAT_RGBA_8888:
    801                     case PIXEL_FORMAT_RGBX_8888:
    802                     case PIXEL_FORMAT_RGB_888:
    803                     case PIXEL_FORMAT_RGB_565:
    804                     case PIXEL_FORMAT_BGRA_8888:
    805                         // We know there's no subsampling of any channels, so we
    806                         // only need to shrink by a half a pixel.
    807                         shrinkAmount = 0.5;
    808                         break;
    809 
    810                     default:
    811                         // If we don't recognize the format, we must assume the
    812                         // worst case (that we care about), which is YUV420.
    813                         shrinkAmount = 1.0;
    814                         break;
    815                 }
    816             }
    817 
    818             // Only shrink the dimensions that are not the size of the buffer.
    819             if (cropRect.width() < bufferWidth) {
    820                 tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
    821                 sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
    822                         bufferWidth;
    823             }
    824             if (cropRect.height() < bufferHeight) {
    825                 ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
    826                         bufferHeight;
    827                 sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
    828                         bufferHeight;
    829             }
    830         }
    831         float crop[16] = {
    832             sx, 0, 0, 0,
    833             0, sy, 0, 0,
    834             0, 0, 1, 0,
    835             tx, ty, 0, 1,
    836         };
    837 
    838         mtxMul(mtxBeforeFlipV, crop, xform);
    839     } else {
    840         for (int i = 0; i < 16; i++) {
    841             mtxBeforeFlipV[i] = xform[i];
    842         }
    843     }
    844 
    845     // SurfaceFlinger expects the top of its window textures to be at a Y
    846     // coordinate of 0, so GLConsumer must behave the same way.  We don't
    847     // want to expose this to applications, however, so we must add an
    848     // additional vertical flip to the transform after all the other transforms.
    849     mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
    850 }
    851 
    852 nsecs_t GLConsumer::getTimestamp() {
    853     ST_LOGV("getTimestamp");
    854     Mutex::Autolock lock(mMutex);
    855     return mCurrentTimestamp;
    856 }
    857 
    858 nsecs_t GLConsumer::getFrameNumber() {
    859     ST_LOGV("getFrameNumber");
    860     Mutex::Autolock lock(mMutex);
    861     return mCurrentFrameNumber;
    862 }
    863 
    864 sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
    865     Mutex::Autolock lock(mMutex);
    866     return (mCurrentTextureImage == NULL) ?
    867             NULL : mCurrentTextureImage->graphicBuffer();
    868 }
    869 
    870 Rect GLConsumer::getCurrentCrop() const {
    871     Mutex::Autolock lock(mMutex);
    872 
    873     Rect outCrop = mCurrentCrop;
    874     if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
    875         int32_t newWidth = mCurrentCrop.width();
    876         int32_t newHeight = mCurrentCrop.height();
    877 
    878         if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
    879             newWidth = newHeight * mDefaultWidth / mDefaultHeight;
    880             ST_LOGV("too wide: newWidth = %d", newWidth);
    881         } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
    882             newHeight = newWidth * mDefaultHeight / mDefaultWidth;
    883             ST_LOGV("too tall: newHeight = %d", newHeight);
    884         }
    885 
    886         // The crop is too wide
    887         if (newWidth < mCurrentCrop.width()) {
    888             int32_t dw = (newWidth - mCurrentCrop.width())/2;
    889             outCrop.left -=dw;
    890             outCrop.right += dw;
    891         // The crop is too tall
    892         } else if (newHeight < mCurrentCrop.height()) {
    893             int32_t dh = (newHeight - mCurrentCrop.height())/2;
    894             outCrop.top -= dh;
    895             outCrop.bottom += dh;
    896         }
    897 
    898         ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
    899             outCrop.left, outCrop.top,
    900             outCrop.right,outCrop.bottom);
    901     }
    902 
    903     return outCrop;
    904 }
    905 
    906 uint32_t GLConsumer::getCurrentTransform() const {
    907     Mutex::Autolock lock(mMutex);
    908     return mCurrentTransform;
    909 }
    910 
    911 uint32_t GLConsumer::getCurrentScalingMode() const {
    912     Mutex::Autolock lock(mMutex);
    913     return mCurrentScalingMode;
    914 }
    915 
    916 sp<Fence> GLConsumer::getCurrentFence() const {
    917     Mutex::Autolock lock(mMutex);
    918     return mCurrentFence;
    919 }
    920 
    921 status_t GLConsumer::doGLFenceWait() const {
    922     Mutex::Autolock lock(mMutex);
    923     return doGLFenceWaitLocked();
    924 }
    925 
    926 status_t GLConsumer::doGLFenceWaitLocked() const {
    927 
    928     EGLDisplay dpy = eglGetCurrentDisplay();
    929     EGLContext ctx = eglGetCurrentContext();
    930 
    931     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
    932         ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
    933         return INVALID_OPERATION;
    934     }
    935 
    936     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
    937         ST_LOGE("doGLFenceWait: invalid current EGLContext");
    938         return INVALID_OPERATION;
    939     }
    940 
    941     if (mCurrentFence->isValid()) {
    942         if (SyncFeatures::getInstance().useWaitSync()) {
    943             // Create an EGLSyncKHR from the current fence.
    944             int fenceFd = mCurrentFence->dup();
    945             if (fenceFd == -1) {
    946                 ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
    947                 return -errno;
    948             }
    949             EGLint attribs[] = {
    950                 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
    951                 EGL_NONE
    952             };
    953             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
    954                     EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
    955             if (sync == EGL_NO_SYNC_KHR) {
    956                 close(fenceFd);
    957                 ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
    958                         eglGetError());
    959                 return UNKNOWN_ERROR;
    960             }
    961 
    962             // XXX: The spec draft is inconsistent as to whether this should
    963             // return an EGLint or void.  Ignore the return value for now, as
    964             // it's not strictly needed.
    965             eglWaitSyncKHR(dpy, sync, 0);
    966             EGLint eglErr = eglGetError();
    967             eglDestroySyncKHR(dpy, sync);
    968             if (eglErr != EGL_SUCCESS) {
    969                 ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
    970                         eglErr);
    971                 return UNKNOWN_ERROR;
    972             }
    973         } else {
    974             status_t err = mCurrentFence->waitForever(
    975                     "GLConsumer::doGLFenceWaitLocked");
    976             if (err != NO_ERROR) {
    977                 ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
    978                 return err;
    979             }
    980         }
    981     }
    982 
    983     return NO_ERROR;
    984 }
    985 
    986 void GLConsumer::freeBufferLocked(int slotIndex) {
    987     ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
    988     if (slotIndex == mCurrentTexture) {
    989         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
    990     }
    991     mEglSlots[slotIndex].mEglImage.clear();
    992     ConsumerBase::freeBufferLocked(slotIndex);
    993 }
    994 
    995 void GLConsumer::abandonLocked() {
    996     ST_LOGV("abandonLocked");
    997     mCurrentTextureImage.clear();
    998     ConsumerBase::abandonLocked();
    999 }
   1000 
   1001 void GLConsumer::setName(const String8& name) {
   1002     Mutex::Autolock _l(mMutex);
   1003     mName = name;
   1004     mConsumer->setConsumerName(name);
   1005 }
   1006 
   1007 status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
   1008     Mutex::Autolock lock(mMutex);
   1009     return mConsumer->setDefaultBufferFormat(defaultFormat);
   1010 }
   1011 
   1012 status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
   1013     Mutex::Autolock lock(mMutex);
   1014     usage |= DEFAULT_USAGE_FLAGS;
   1015     return mConsumer->setConsumerUsageBits(usage);
   1016 }
   1017 
   1018 status_t GLConsumer::setTransformHint(uint32_t hint) {
   1019     Mutex::Autolock lock(mMutex);
   1020     return mConsumer->setTransformHint(hint);
   1021 }
   1022 
   1023 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
   1024 {
   1025     result.appendFormat(
   1026        "%smTexName=%d mCurrentTexture=%d\n"
   1027        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
   1028        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
   1029        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
   1030        mCurrentTransform);
   1031 
   1032     ConsumerBase::dumpLocked(result, prefix);
   1033 }
   1034 
   1035 static void mtxMul(float out[16], const float a[16], const float b[16]) {
   1036     out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
   1037     out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
   1038     out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
   1039     out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
   1040 
   1041     out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
   1042     out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
   1043     out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
   1044     out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
   1045 
   1046     out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
   1047     out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
   1048     out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
   1049     out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
   1050 
   1051     out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
   1052     out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
   1053     out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
   1054     out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
   1055 }
   1056 
   1057 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
   1058     mGraphicBuffer(graphicBuffer),
   1059     mEglImage(EGL_NO_IMAGE_KHR),
   1060     mEglDisplay(EGL_NO_DISPLAY) {
   1061 }
   1062 
   1063 GLConsumer::EglImage::~EglImage() {
   1064     if (mEglImage != EGL_NO_IMAGE_KHR) {
   1065         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
   1066            ALOGE("~EglImage: eglDestroyImageKHR failed");
   1067         }
   1068     }
   1069 }
   1070 
   1071 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
   1072                                               const Rect& cropRect,
   1073                                               bool forceCreation) {
   1074     // If there's an image and it's no longer valid, destroy it.
   1075     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
   1076     bool displayInvalid = mEglDisplay != eglDisplay;
   1077     bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
   1078     if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
   1079         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
   1080            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
   1081         }
   1082         mEglImage = EGL_NO_IMAGE_KHR;
   1083         mEglDisplay = EGL_NO_DISPLAY;
   1084     }
   1085 
   1086     // If there's no image, create one.
   1087     if (mEglImage == EGL_NO_IMAGE_KHR) {
   1088         mEglDisplay = eglDisplay;
   1089         mCropRect = cropRect;
   1090         mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
   1091     }
   1092 
   1093     // Fail if we can't create a valid image.
   1094     if (mEglImage == EGL_NO_IMAGE_KHR) {
   1095         mEglDisplay = EGL_NO_DISPLAY;
   1096         mCropRect.makeInvalid();
   1097         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
   1098         ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
   1099             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
   1100             buffer->getUsage(), buffer->getPixelFormat());
   1101         return UNKNOWN_ERROR;
   1102     }
   1103 
   1104     return OK;
   1105 }
   1106 
   1107 void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
   1108     glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage);
   1109 }
   1110 
   1111 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
   1112         const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
   1113     EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
   1114     EGLint attrs[] = {
   1115         EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
   1116         EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
   1117         EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
   1118         EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
   1119         EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
   1120         EGL_NONE,
   1121     };
   1122     if (!crop.isValid()) {
   1123         // No crop rect to set, so terminate the attrib array before the crop.
   1124         attrs[2] = EGL_NONE;
   1125     } else if (!isEglImageCroppable(crop)) {
   1126         // The crop rect is not at the origin, so we can't set the crop on the
   1127         // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
   1128         // extension.  In the future we can add a layered extension that
   1129         // removes this restriction if there is hardware that can support it.
   1130         attrs[2] = EGL_NONE;
   1131     }
   1132     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
   1133             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
   1134     if (image == EGL_NO_IMAGE_KHR) {
   1135         EGLint error = eglGetError();
   1136         ALOGE("error creating EGLImage: %#x", error);
   1137     }
   1138     return image;
   1139 }
   1140 
   1141 }; // namespace android
   1142