Home | History | Annotate | Download | only in surfacetexture
      1 /*
      2  * Copyright (C) 2018 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 #include <inttypes.h>
     18 
     19 #include <EGL/egl.h>
     20 #include <EGL/eglext.h>
     21 #include <GLES2/gl2.h>
     22 #include <GLES2/gl2ext.h>
     23 #include <cutils/compiler.h>
     24 #include <gui/BufferItem.h>
     25 #include <gui/BufferQueue.h>
     26 #include <private/gui/SyncFeatures.h>
     27 #include "EGLConsumer.h"
     28 #include "SurfaceTexture.h"
     29 
     30 #include <utils/Log.h>
     31 #include <utils/String8.h>
     32 #include <utils/Trace.h>
     33 
     34 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
     35 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
     36 
     37 namespace android {
     38 
     39 // Macros for including the SurfaceTexture name in log messages
     40 #define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__)
     41 #define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__)
     42 #define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__)
     43 #define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
     44 
     45 static const struct {
     46     uint32_t width, height;
     47     char const* bits;
     48 } kDebugData = {15, 12,
     49                 "_______________"
     50                 "_______________"
     51                 "_____XX_XX_____"
     52                 "__X_X_____X_X__"
     53                 "__X_XXXXXXX_X__"
     54                 "__XXXXXXXXXXX__"
     55                 "___XX_XXX_XX___"
     56                 "____XXXXXXX____"
     57                 "_____X___X_____"
     58                 "____X_____X____"
     59                 "_______________"
     60                 "_______________"};
     61 
     62 Mutex EGLConsumer::sStaticInitLock;
     63 sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer;
     64 
     65 static bool hasEglProtectedContentImpl() {
     66     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     67     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
     68     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
     69     size_t extsLen = strlen(exts);
     70     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
     71     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
     72     bool atEnd = (cropExtLen + 1) < extsLen &&
     73                  !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
     74     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
     75     return equal || atStart || atEnd || inMiddle;
     76 }
     77 
     78 static bool hasEglProtectedContent() {
     79     // Only compute whether the extension is present once the first time this
     80     // function is called.
     81     static bool hasIt = hasEglProtectedContentImpl();
     82     return hasIt;
     83 }
     84 
     85 EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {}
     86 
     87 status_t EGLConsumer::updateTexImage(SurfaceTexture& st) {
     88     // Make sure the EGL state is the same as in previous calls.
     89     status_t err = checkAndUpdateEglStateLocked(st);
     90     if (err != NO_ERROR) {
     91         return err;
     92     }
     93 
     94     BufferItem item;
     95 
     96     // Acquire the next buffer.
     97     // In asynchronous mode the list is guaranteed to be one buffer
     98     // deep, while in synchronous mode we use the oldest buffer.
     99     err = st.acquireBufferLocked(&item, 0);
    100     if (err != NO_ERROR) {
    101         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
    102             // We always bind the texture even if we don't update its contents.
    103             EGC_LOGV("updateTexImage: no buffers were available");
    104             glBindTexture(st.mTexTarget, st.mTexName);
    105             err = NO_ERROR;
    106         } else {
    107             EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
    108         }
    109         return err;
    110     }
    111 
    112     // Release the previous buffer.
    113     err = updateAndReleaseLocked(item, nullptr, st);
    114     if (err != NO_ERROR) {
    115         // We always bind the texture.
    116         glBindTexture(st.mTexTarget, st.mTexName);
    117         return err;
    118     }
    119 
    120     // Bind the new buffer to the GL texture, and wait until it's ready.
    121     return bindTextureImageLocked(st);
    122 }
    123 
    124 status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) {
    125     // Make sure the EGL state is the same as in previous calls.
    126     status_t err = NO_ERROR;
    127 
    128     // if we're detached, no need to validate EGL's state -- we won't use it.
    129     if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
    130         err = checkAndUpdateEglStateLocked(st, true);
    131         if (err != NO_ERROR) {
    132             return err;
    133         }
    134     }
    135 
    136     // Update the EGLConsumer state.
    137     int buf = st.mCurrentTexture;
    138     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
    139         EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode);
    140 
    141         // if we're detached, we just use the fence that was created in detachFromContext()
    142         // so... basically, nothing more to do here.
    143         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
    144             // Do whatever sync ops we need to do before releasing the slot.
    145             err = syncForReleaseLocked(mEglDisplay, st);
    146             if (err != NO_ERROR) {
    147                 EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
    148                 return err;
    149             }
    150         }
    151 
    152         err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay,
    153                                      EGL_NO_SYNC_KHR);
    154         if (err < NO_ERROR) {
    155             EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err);
    156             return err;
    157         }
    158 
    159         if (mReleasedTexImage == nullptr) {
    160             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
    161         }
    162 
    163         st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
    164         mCurrentTextureImage = mReleasedTexImage;
    165         st.mCurrentCrop.makeInvalid();
    166         st.mCurrentTransform = 0;
    167         st.mCurrentTimestamp = 0;
    168         st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
    169         st.mCurrentFence = Fence::NO_FENCE;
    170         st.mCurrentFenceTime = FenceTime::NO_FENCE;
    171 
    172         // detached, don't touch the texture (and we may not even have an
    173         // EGLDisplay here.
    174         if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
    175             // This binds a dummy buffer (mReleasedTexImage).
    176             status_t result = bindTextureImageLocked(st);
    177             if (result != NO_ERROR) {
    178                 return result;
    179             }
    180         }
    181     }
    182 
    183     return NO_ERROR;
    184 }
    185 
    186 sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() {
    187     Mutex::Autolock _l(sStaticInitLock);
    188     if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
    189         // The first time, create the debug texture in case the application
    190         // continues to use it.
    191         sp<GraphicBuffer> buffer = new GraphicBuffer(
    192                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
    193                 GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]");
    194         uint32_t* bits;
    195         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
    196         uint32_t stride = buffer->getStride();
    197         uint32_t height = buffer->getHeight();
    198         memset(bits, 0, stride * height * 4);
    199         for (uint32_t y = 0; y < kDebugData.height; y++) {
    200             for (uint32_t x = 0; x < kDebugData.width; x++) {
    201                 bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000
    202                                                                              : 0xFFFFFFFF;
    203             }
    204             bits += stride;
    205         }
    206         buffer->unlock();
    207         sReleasedTexImageBuffer = buffer;
    208     }
    209     return sReleasedTexImageBuffer;
    210 }
    211 
    212 void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) {
    213     // If item->mGraphicBuffer is not null, this buffer has not been acquired
    214     // before, so any prior EglImage created is using a stale buffer. This
    215     // replaces any old EglImage with a new one (using the new buffer).
    216     int slot = item->mSlot;
    217     if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) {
    218         mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
    219     }
    220 }
    221 
    222 void EGLConsumer::onReleaseBufferLocked(int buf) {
    223     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
    224 }
    225 
    226 status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
    227                                              SurfaceTexture& st) {
    228     status_t err = NO_ERROR;
    229 
    230     int slot = item.mSlot;
    231 
    232     if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) {
    233         EGC_LOGE(
    234                 "updateAndRelease: EGLConsumer is not attached to an OpenGL "
    235                 "ES context");
    236         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
    237         return INVALID_OPERATION;
    238     }
    239 
    240     // Confirm state.
    241     err = checkAndUpdateEglStateLocked(st);
    242     if (err != NO_ERROR) {
    243         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
    244         return err;
    245     }
    246 
    247     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
    248     // if nessessary, for the gralloc buffer currently in the slot in
    249     // ConsumerBase.
    250     // We may have to do this even when item.mGraphicBuffer == NULL (which
    251     // means the buffer was previously acquired).
    252     err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
    253     if (err != NO_ERROR) {
    254         EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
    255                  slot);
    256         st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
    257         return UNKNOWN_ERROR;
    258     }
    259 
    260     // Do whatever sync ops we need to do before releasing the old slot.
    261     if (slot != st.mCurrentTexture) {
    262         err = syncForReleaseLocked(mEglDisplay, st);
    263         if (err != NO_ERROR) {
    264             // Release the buffer we just acquired.  It's not safe to
    265             // release the old buffer, so instead we just drop the new frame.
    266             // As we are still under lock since acquireBuffer, it is safe to
    267             // release by slot.
    268             st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay,
    269                                    EGL_NO_SYNC_KHR);
    270             return err;
    271         }
    272     }
    273 
    274     EGC_LOGV(
    275             "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture,
    276             mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr,
    277             slot, st.mSlots[slot].mGraphicBuffer->handle);
    278 
    279     // Hang onto the pointer so that it isn't freed in the call to
    280     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
    281     // the same.
    282     sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
    283 
    284     // release old buffer
    285     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    286         if (pendingRelease == nullptr) {
    287             status_t status = st.releaseBufferLocked(
    288                     st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay,
    289                     mEglSlots[st.mCurrentTexture].mEglFence);
    290             if (status < NO_ERROR) {
    291                 EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
    292                          status);
    293                 err = status;
    294                 // keep going, with error raised [?]
    295             }
    296         } else {
    297             pendingRelease->currentTexture = st.mCurrentTexture;
    298             pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
    299             pendingRelease->display = mEglDisplay;
    300             pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence;
    301             pendingRelease->isPending = true;
    302         }
    303     }
    304 
    305     // Update the EGLConsumer state.
    306     st.mCurrentTexture = slot;
    307     mCurrentTextureImage = nextTextureImage;
    308     st.mCurrentCrop = item.mCrop;
    309     st.mCurrentTransform = item.mTransform;
    310     st.mCurrentScalingMode = item.mScalingMode;
    311     st.mCurrentTimestamp = item.mTimestamp;
    312     st.mCurrentDataSpace = item.mDataSpace;
    313     st.mCurrentFence = item.mFence;
    314     st.mCurrentFenceTime = item.mFenceTime;
    315     st.mCurrentFrameNumber = item.mFrameNumber;
    316 
    317     st.computeCurrentTransformMatrixLocked();
    318 
    319     return err;
    320 }
    321 
    322 status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) {
    323     if (mEglDisplay == EGL_NO_DISPLAY) {
    324         ALOGE("bindTextureImage: invalid display");
    325         return INVALID_OPERATION;
    326     }
    327 
    328     GLenum error;
    329     while ((error = glGetError()) != GL_NO_ERROR) {
    330         EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
    331     }
    332 
    333     glBindTexture(st.mTexTarget, st.mTexName);
    334     if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
    335         EGC_LOGE("bindTextureImage: no currently-bound texture");
    336         return NO_INIT;
    337     }
    338 
    339     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
    340     if (err != NO_ERROR) {
    341         EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
    342                  st.mCurrentTexture);
    343         return UNKNOWN_ERROR;
    344     }
    345     mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
    346 
    347     // In the rare case that the display is terminated and then initialized
    348     // again, we can't detect that the display changed (it didn't), but the
    349     // image is invalid. In this case, repeat the exact same steps while
    350     // forcing the creation of a new image.
    351     if ((error = glGetError()) != GL_NO_ERROR) {
    352         glBindTexture(st.mTexTarget, st.mTexName);
    353         status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
    354         if (result != NO_ERROR) {
    355             EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
    356                      st.mCurrentTexture);
    357             return UNKNOWN_ERROR;
    358         }
    359         mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
    360         if ((error = glGetError()) != GL_NO_ERROR) {
    361             EGC_LOGE("bindTextureImage: error binding external image: %#04x", error);
    362             return UNKNOWN_ERROR;
    363         }
    364     }
    365 
    366     // Wait for the new buffer to be ready.
    367     return doGLFenceWaitLocked(st);
    368 }
    369 
    370 status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) {
    371     EGLDisplay dpy = eglGetCurrentDisplay();
    372     EGLContext ctx = eglGetCurrentContext();
    373 
    374     if (!contextCheck) {
    375         // if this is the first time we're called, mEglDisplay/mEglContext have
    376         // never been set, so don't error out (below).
    377         if (mEglDisplay == EGL_NO_DISPLAY) {
    378             mEglDisplay = dpy;
    379         }
    380         if (mEglContext == EGL_NO_CONTEXT) {
    381             mEglContext = ctx;
    382         }
    383     }
    384 
    385     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
    386         EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
    387         return INVALID_OPERATION;
    388     }
    389 
    390     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
    391         EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
    392         return INVALID_OPERATION;
    393     }
    394 
    395     mEglDisplay = dpy;
    396     mEglContext = ctx;
    397     return NO_ERROR;
    398 }
    399 
    400 status_t EGLConsumer::detachFromContext(SurfaceTexture& st) {
    401     EGLDisplay dpy = eglGetCurrentDisplay();
    402     EGLContext ctx = eglGetCurrentContext();
    403 
    404     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
    405         EGC_LOGE("detachFromContext: invalid current EGLDisplay");
    406         return INVALID_OPERATION;
    407     }
    408 
    409     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
    410         EGC_LOGE("detachFromContext: invalid current EGLContext");
    411         return INVALID_OPERATION;
    412     }
    413 
    414     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
    415         status_t err = syncForReleaseLocked(dpy, st);
    416         if (err != OK) {
    417             return err;
    418         }
    419 
    420         glDeleteTextures(1, &st.mTexName);
    421     }
    422 
    423     mEglDisplay = EGL_NO_DISPLAY;
    424     mEglContext = EGL_NO_CONTEXT;
    425 
    426     return OK;
    427 }
    428 
    429 status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) {
    430     // Initialize mCurrentTextureImage if there is a current buffer from past attached state.
    431     int slot = st.mCurrentTexture;
    432     if (slot != BufferItem::INVALID_BUFFER_SLOT) {
    433         if (!mEglSlots[slot].mEglImage.get()) {
    434             mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
    435         }
    436         mCurrentTextureImage = mEglSlots[slot].mEglImage;
    437     }
    438 
    439     EGLDisplay dpy = eglGetCurrentDisplay();
    440     EGLContext ctx = eglGetCurrentContext();
    441 
    442     if (dpy == EGL_NO_DISPLAY) {
    443         EGC_LOGE("attachToContext: invalid current EGLDisplay");
    444         return INVALID_OPERATION;
    445     }
    446 
    447     if (ctx == EGL_NO_CONTEXT) {
    448         EGC_LOGE("attachToContext: invalid current EGLContext");
    449         return INVALID_OPERATION;
    450     }
    451 
    452     // We need to bind the texture regardless of whether there's a current
    453     // buffer.
    454     glBindTexture(st.mTexTarget, GLuint(tex));
    455 
    456     mEglDisplay = dpy;
    457     mEglContext = ctx;
    458     st.mTexName = tex;
    459     st.mOpMode = SurfaceTexture::OpMode::attachedToGL;
    460 
    461     if (mCurrentTextureImage != nullptr) {
    462         // This may wait for a buffer a second time. This is likely required if
    463         // this is a different context, since otherwise the wait could be skipped
    464         // by bouncing through another context. For the same context the extra
    465         // wait is redundant.
    466         status_t err = bindTextureImageLocked(st);
    467         if (err != NO_ERROR) {
    468             return err;
    469         }
    470     }
    471 
    472     return OK;
    473 }
    474 
    475 status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) {
    476     EGC_LOGV("syncForReleaseLocked");
    477 
    478     if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
    479         if (SyncFeatures::getInstance().useNativeFenceSync()) {
    480             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
    481             if (sync == EGL_NO_SYNC_KHR) {
    482                 EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
    483                 return UNKNOWN_ERROR;
    484             }
    485             glFlush();
    486             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
    487             eglDestroySyncKHR(dpy, sync);
    488             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
    489                 EGC_LOGE(
    490                         "syncForReleaseLocked: error dup'ing native fence "
    491                         "fd: %#x",
    492                         eglGetError());
    493                 return UNKNOWN_ERROR;
    494             }
    495             sp<Fence> fence(new Fence(fenceFd));
    496             status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
    497                                                     mCurrentTextureImage->graphicBuffer(), fence);
    498             if (err != OK) {
    499                 EGC_LOGE(
    500                         "syncForReleaseLocked: error adding release fence: "
    501                         "%s (%d)",
    502                         strerror(-err), err);
    503                 return err;
    504             }
    505         } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
    506             EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence;
    507             if (fence != EGL_NO_SYNC_KHR) {
    508                 // There is already a fence for the current slot.  We need to
    509                 // wait on that before replacing it with another fence to
    510                 // ensure that all outstanding buffer accesses have completed
    511                 // before the producer accesses it.
    512                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
    513                 if (result == EGL_FALSE) {
    514                     EGC_LOGE(
    515                             "syncForReleaseLocked: error waiting for previous "
    516                             "fence: %#x",
    517                             eglGetError());
    518                     return UNKNOWN_ERROR;
    519                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
    520                     EGC_LOGE(
    521                             "syncForReleaseLocked: timeout waiting for previous "
    522                             "fence");
    523                     return TIMED_OUT;
    524                 }
    525                 eglDestroySyncKHR(dpy, fence);
    526             }
    527 
    528             // Create a fence for the outstanding accesses in the current
    529             // OpenGL ES context.
    530             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
    531             if (fence == EGL_NO_SYNC_KHR) {
    532                 EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
    533                 return UNKNOWN_ERROR;
    534             }
    535             glFlush();
    536             mEglSlots[st.mCurrentTexture].mEglFence = fence;
    537         }
    538     }
    539 
    540     return OK;
    541 }
    542 
    543 status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const {
    544     EGLDisplay dpy = eglGetCurrentDisplay();
    545     EGLContext ctx = eglGetCurrentContext();
    546 
    547     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
    548         EGC_LOGE("doGLFenceWait: invalid current EGLDisplay");
    549         return INVALID_OPERATION;
    550     }
    551 
    552     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
    553         EGC_LOGE("doGLFenceWait: invalid current EGLContext");
    554         return INVALID_OPERATION;
    555     }
    556 
    557     if (st.mCurrentFence->isValid()) {
    558         if (SyncFeatures::getInstance().useWaitSync() &&
    559             SyncFeatures::getInstance().useNativeFenceSync()) {
    560             // Create an EGLSyncKHR from the current fence.
    561             int fenceFd = st.mCurrentFence->dup();
    562             if (fenceFd == -1) {
    563                 EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
    564                 return -errno;
    565             }
    566             EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
    567             EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
    568             if (sync == EGL_NO_SYNC_KHR) {
    569                 close(fenceFd);
    570                 EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
    571                 return UNKNOWN_ERROR;
    572             }
    573 
    574             // XXX: The spec draft is inconsistent as to whether this should
    575             // return an EGLint or void.  Ignore the return value for now, as
    576             // it's not strictly needed.
    577             eglWaitSyncKHR(dpy, sync, 0);
    578             EGLint eglErr = eglGetError();
    579             eglDestroySyncKHR(dpy, sync);
    580             if (eglErr != EGL_SUCCESS) {
    581                 EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
    582                 return UNKNOWN_ERROR;
    583             }
    584         } else {
    585             status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked");
    586             if (err != NO_ERROR) {
    587                 EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
    588                 return err;
    589             }
    590         }
    591     }
    592 
    593     return NO_ERROR;
    594 }
    595 
    596 void EGLConsumer::onFreeBufferLocked(int slotIndex) {
    597     mEglSlots[slotIndex].mEglImage.clear();
    598 }
    599 
    600 void EGLConsumer::onAbandonLocked() {
    601     mCurrentTextureImage.clear();
    602 }
    603 
    604 EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
    605         : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {}
    606 
    607 EGLConsumer::EglImage::~EglImage() {
    608     if (mEglImage != EGL_NO_IMAGE_KHR) {
    609         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
    610             ALOGE("~EglImage: eglDestroyImageKHR failed");
    611         }
    612         eglTerminate(mEglDisplay);
    613     }
    614 }
    615 
    616 status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) {
    617     // If there's an image and it's no longer valid, destroy it.
    618     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
    619     bool displayInvalid = mEglDisplay != eglDisplay;
    620     if (haveImage && (displayInvalid || forceCreation)) {
    621         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
    622             ALOGE("createIfNeeded: eglDestroyImageKHR failed");
    623         }
    624         eglTerminate(mEglDisplay);
    625         mEglImage = EGL_NO_IMAGE_KHR;
    626         mEglDisplay = EGL_NO_DISPLAY;
    627     }
    628 
    629     // If there's no image, create one.
    630     if (mEglImage == EGL_NO_IMAGE_KHR) {
    631         mEglDisplay = eglDisplay;
    632         mEglImage = createImage(mEglDisplay, mGraphicBuffer);
    633     }
    634 
    635     // Fail if we can't create a valid image.
    636     if (mEglImage == EGL_NO_IMAGE_KHR) {
    637         mEglDisplay = EGL_NO_DISPLAY;
    638         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
    639         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
    640               buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
    641               buffer->getPixelFormat());
    642         return UNKNOWN_ERROR;
    643     }
    644 
    645     return OK;
    646 }
    647 
    648 void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
    649     glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
    650 }
    651 
    652 EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy,
    653                                                const sp<GraphicBuffer>& graphicBuffer) {
    654     EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
    655     const bool createProtectedImage =
    656             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
    657     EGLint attrs[] = {
    658             EGL_IMAGE_PRESERVED_KHR,
    659             EGL_TRUE,
    660             createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
    661             createProtectedImage ? EGL_TRUE : EGL_NONE,
    662             EGL_NONE,
    663     };
    664     eglInitialize(dpy, nullptr, nullptr);
    665     EGLImageKHR image =
    666             eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
    667     if (image == EGL_NO_IMAGE_KHR) {
    668         EGLint error = eglGetError();
    669         ALOGE("error creating EGLImage: %#x", error);
    670         eglTerminate(dpy);
    671     }
    672     return image;
    673 }
    674 
    675 }  // namespace android
    676