status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) {
    status_t err = NO_ERROR;
    if (fenceFd >= 0) {
        sp<Fence> fence(new Fence(fenceFd));
        if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
#if ANDROID_VERSION >= 19
            status_t err = addReleaseFence(mCurrentBufferSlot, mCurrentBuffer,  fence);
#else
            status_t err = addReleaseFence(mCurrentBufferSlot, fence);
#endif
            ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
                    strerror(-err), err);
        }
    }
    return err;
}
void FramebufferSurface::onFrameCommitted() {
    sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
    if (fence->isValid() &&
            mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
        status_t err = addReleaseFence(mCurrentBufferSlot,
                mCurrentBuffer, fence);
        ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
                strerror(-err), err);
    }
}
void SurfaceTexture::setReleaseFence(int fenceFd) {
    sp<Fence> fence(new Fence(fenceFd));
    if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
        return;
    status_t err = addReleaseFence(mCurrentTexture, fence);
    if (err != OK) {
        ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
                strerror(-err), err);
    }
}
void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
    if (fence->isValid() &&
            mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
        status_t err = addReleaseFence(mCurrentTexture, fence);
        if (err != OK) {
            ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
                    strerror(-err), err);
        }
    }
}
status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter, bool skipSync) {
#else
status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter, bool skipSync, bool deferConversion) {
#endif
    ATRACE_CALL();
    ST_LOGV("updateTexImage");
    Mutex::Autolock lock(mMutex);

    status_t err = NO_ERROR;

    if (mAbandoned) {
        ST_LOGE("updateTexImage: SurfaceTexture is abandoned!");
        return NO_INIT;
    }

    if (!mAttached) {
        ST_LOGE("updateTexImage: SurfaceTexture is not attached to an OpenGL "
                "ES context");
        return INVALID_OPERATION;
    }

    EGLDisplay dpy = eglGetCurrentDisplay();
    EGLContext ctx = eglGetCurrentContext();

    if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
            dpy == EGL_NO_DISPLAY) {
        ST_LOGE("updateTexImage: invalid current EGLDisplay");
        return INVALID_OPERATION;
    }

    if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
            ctx == EGL_NO_CONTEXT) {
        ST_LOGE("updateTexImage: invalid current EGLContext");
        return INVALID_OPERATION;
    }

    mEglDisplay = dpy;
    mEglContext = ctx;

    BufferQueue::BufferItem item;

    // In asynchronous mode the list is guaranteed to be one buffer
    // deep, while in synchronous mode we use the oldest buffer.
    err = acquireBufferLocked(&item);
    if (err == NO_ERROR) {
        int buf = item.mBuf;

#ifdef STE_HARDWARE
        EGLImageKHR image;
        if (conversionIsNeeded(mSlots[buf].mGraphicBuffer)) {
            mNeedsConversion = deferConversion;
            // If color conversion is needed we can't use the graphic buffers
            // located in mSlots for the textures (wrong color format). Instead
            // color convert it into a buffer in mBlitSlots and use that instead.
            image = mBlitSlots[mNextBlitSlot].mEglImage;

            // If there exists an image already, make sure that
            // the dimensions match the current source buffer.
            // Otherwise, destroy the buffer and let a new one be allocated.
            if (image != EGL_NO_IMAGE_KHR &&
                    mSlots[buf].mGraphicBuffer != NULL &&
                    mBlitSlots[mNextBlitSlot].mGraphicBuffer != NULL) {
                sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer;
                sp<GraphicBuffer> &bltBuf =
                    mBlitSlots[mNextBlitSlot].mGraphicBuffer;
                if (srcBuf->getWidth() != bltBuf->getWidth() ||
                        srcBuf->getHeight() != bltBuf->getHeight()) {
                    eglDestroyImageKHR(mBlitSlots[mNextBlitSlot].mEglDisplay,
                        image);
                    mBlitSlots[mNextBlitSlot].mEglImage = EGL_NO_IMAGE_KHR;
                    mBlitSlots[mNextBlitSlot].mGraphicBuffer = NULL;
                    image = EGL_NO_IMAGE_KHR;
                }
            }
            if (image == EGL_NO_IMAGE_KHR) {
                sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer;
                status_t res = 0;

                sp<GraphicBuffer> blitBuffer(
                        mGraphicBufferAlloc->createGraphicBuffer(
                                srcBuf->getWidth(), srcBuf->getHeight(),
                                PIXEL_FORMAT_RGBA_8888, srcBuf->getUsage(),
                                &res));
                if (blitBuffer == 0) {
                    ST_LOGE("updateTexImage: SurfaceComposer::createGraphicBuffer failed");
                    return NO_MEMORY;
                }
                if (res != NO_ERROR) {
                    ST_LOGW("updateTexImage: SurfaceComposer::createGraphicBuffer error=%#04x", res);
                }
                mBlitSlots[mNextBlitSlot].mGraphicBuffer = blitBuffer;

                EGLDisplay dpy = eglGetCurrentDisplay();
                image = createImage(dpy, blitBuffer);
                mBlitSlots[mNextBlitSlot].mEglImage = image;
                mBlitSlots[mNextBlitSlot].mEglDisplay = dpy;
            }

            if (deferConversion) {
                item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
                mConversionSrcSlot = buf;
                mConversionBltSlot = mNextBlitSlot;
                // At this point item.mGraphicBuffer and image do not point
                // at matching buffers. This is intentional as this
                // surface might end up being taken care of by HWComposer,
                // which needs access to the original buffer.
                // GL however, is fed an EGLImage that is created from
                // a conversion buffer. It will have its
                // content updated once the surface is actually drawn
                // in Layer::onDraw()
            } else {
                if (convert(mSlots[buf].mGraphicBuffer,
                        mBlitSlots[mNextBlitSlot].mGraphicBuffer) != OK) {
                    ALOGE("updateTexImage: convert failed");
                    return UNKNOWN_ERROR;
                }
                item.mGraphicBuffer = mBlitSlots[mNextBlitSlot].mGraphicBuffer;
            }
            // mBlitSlots contains several buffers (NUM_BLIT_BUFFER_SLOTS),
            // advance (potentially wrap) the index
            mNextBlitSlot = (mNextBlitSlot + 1) % BufferQueue::NUM_BLIT_BUFFER_SLOTS;
        } else {
            mNeedsConversion = false;
            image = mEglSlots[buf].mEglImage;
            item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
            if (image == EGL_NO_IMAGE_KHR) {
                EGLDisplay dpy = eglGetCurrentDisplay();
                if (item.mGraphicBuffer == 0) {
                    ST_LOGE("buffer at slot %d is null", buf);
                    return BAD_VALUE;
                }
                image = createImage(dpy, item.mGraphicBuffer);
                mEglSlots[buf].mEglImage = image;
                mEglDisplay = dpy;
                if (image == EGL_NO_IMAGE_KHR) {
                    // NOTE: if dpy was invalid, createImage() is guaranteed to
                    // fail. so we'd end up here.
                    return -EINVAL;
                }
            }
        }
#endif

        // we call the rejecter here, in case the caller has a reason to
        // not accept this buffer. this is used by SurfaceFlinger to
        // reject buffers which have the wrong size
#ifdef STE_HARDWARE
        if (rejecter && rejecter->reject(item.mGraphicBuffer, item)) {
#else
        if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
#endif
            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
            glBindTexture(mTexTarget, mTexName);
            return NO_ERROR;
        }

        GLint error;
        while ((error = glGetError()) != GL_NO_ERROR) {
            ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
        }

#ifndef STE_HARDWARE
        EGLImageKHR image = mEglSlots[buf].mEglImage;
#endif
        glBindTexture(mTexTarget, mTexName);
        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);

        while ((error = glGetError()) != GL_NO_ERROR) {
            ST_LOGE("updateTexImage: error binding external texture image %p "
                    "(slot %d): %#04x", image, buf, error);
            err = UNKNOWN_ERROR;
        }

        if (err == NO_ERROR) {
            err = syncForReleaseLocked(dpy);
        }

        if (err != NO_ERROR) {
            // Release the buffer we just acquired.  It's not safe to
            // release the old buffer, so instead we just drop the new frame.
            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
            return err;
        }

        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
                mCurrentTexture,
                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
                buf, mSlots[buf].mGraphicBuffer->handle);

        // release old buffer
        if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
            status_t status = releaseBufferLocked(mCurrentTexture, dpy,
                    mEglSlots[mCurrentTexture].mEglFence);
            if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
                ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
                       strerror(-status), status);
                err = status;
            }
        }

        // Update the SurfaceTexture state.
        mCurrentTexture = buf;
#ifndef STE_HARDWARE
        mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
#else
        mCurrentTextureBuf = item.mGraphicBuffer;
#endif
        mCurrentCrop = item.mCrop;
        mCurrentTransform = item.mTransform;
        mCurrentScalingMode = item.mScalingMode;
        mCurrentTimestamp = item.mTimestamp;
        mCurrentFence = item.mFence;
        if (!skipSync) {
            // SurfaceFlinger needs to lazily perform GLES synchronization
            // only when it's actually going to use GLES for compositing.
            // Eventually SurfaceFlinger should have its own consumer class,
            // but for now we'll just hack it in to SurfaceTexture.
            // SurfaceFlinger is responsible for calling doGLFenceWait before
            // texturing from this SurfaceTexture.
            doGLFenceWaitLocked();
        }
        computeCurrentTransformMatrixLocked();
    } else  {
        if (err < 0) {
            ST_LOGE("updateTexImage: acquire failed: %s (%d)",
                strerror(-err), err);
            return err;
        }
        // We always bind the texture even if we don't update its contents.
        glBindTexture(mTexTarget, mTexName);
        return OK;
    }

    return err;
}

void SurfaceTexture::setReleaseFence(int fenceFd) {
    sp<Fence> fence(new Fence(fenceFd));
    if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
        return;
    status_t err = addReleaseFence(mCurrentTexture, fence);
    if (err != OK) {
        ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
                strerror(-err), err);
    }
}