SurfaceTexture.cpp revision d369dc42506ec003f1839bb9e27edada411324b5
168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis/*
268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * Copyright (C) 2010 The Android Open Source Project
368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis *
468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * you may not use this file except in compliance with the License.
668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * You may obtain a copy of the License at
768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis *
868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis *
1068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * Unless required by applicable law or agreed to in writing, software
1168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
1268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * See the License for the specific language governing permissions and
1468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis * limitations under the License.
1568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis */
1668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
1768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#define LOG_TAG "SurfaceTexture"
187dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis//#define LOG_NDEBUG 0
1968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
2068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#define GL_GLEXT_PROTOTYPES
2168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#define EGL_EGLEXT_PROTOTYPES
2268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
2368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <EGL/egl.h>
2468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <EGL/eglext.h>
2568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <GLES2/gl2.h>
2668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <GLES2/gl2ext.h>
2768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
2868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <gui/SurfaceTexture.h>
2968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
3068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <surfaceflinger/ISurfaceComposer.h>
3168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <surfaceflinger/SurfaceComposerClient.h>
3268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
3368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis#include <utils/Log.h>
3468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
3568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisnamespace android {
3668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
3768e4a7ac849b681b1fb769857fc04f64262480c4Jamie GennisSurfaceTexture::SurfaceTexture(GLuint tex) :
3868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
3968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
407dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::SurfaceTexture");
41fd804f31a36c31661859b53bbee1bb408462ddcaJamie Gennis    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
42fd804f31a36c31661859b53bbee1bb408462ddcaJamie Gennis        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
43fd804f31a36c31661859b53bbee1bb408462ddcaJamie Gennis        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
44fd804f31a36c31661859b53bbee1bb408462ddcaJamie Gennis        mSlots[i].mOwnedByClient = false;
45fd804f31a36c31661859b53bbee1bb408462ddcaJamie Gennis    }
4668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
4768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
4868e4a7ac849b681b1fb769857fc04f64262480c4Jamie GennisSurfaceTexture::~SurfaceTexture() {
497dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::~SurfaceTexture");
5068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    freeAllBuffers();
5168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
5268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
5368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::setBufferCount(int bufferCount) {
547dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::setBufferCount");
5568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
5668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    freeAllBuffers();
5768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mBufferCount = bufferCount;
58d369dc42506ec003f1839bb9e27edada411324b5Jamie Gennis    mCurrentTexture = INVALID_BUFFER_SLOT;
59d369dc42506ec003f1839bb9e27edada411324b5Jamie Gennis    mLastQueued = INVALID_BUFFER_SLOT;
6068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
6168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
6268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
6368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennissp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
6468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
657dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::requestBuffer");
6668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
6768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (buf < 0 || mBufferCount <= buf) {
6868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
6968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                mBufferCount, buf);
7068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return 0;
7168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
7268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    usage |= GraphicBuffer::USAGE_HW_TEXTURE;
7368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
7468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
7568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            format, usage));
7668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (graphicBuffer == 0) {
7768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
7868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    } else {
7968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        mSlots[buf].mGraphicBuffer = graphicBuffer;
8068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
8168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
8268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
8368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
8468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        }
8568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
8668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return graphicBuffer;
8768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
8868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
8968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::dequeueBuffer(int *buf) {
907dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::dequeueBuffer");
9168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
9268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    int found = INVALID_BUFFER_SLOT;
9368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    for (int i = 0; i < mBufferCount; i++) {
9468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
9568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[i].mOwnedByClient = true;
9668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            found = i;
9768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            break;
9868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        }
9968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
10068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (found == INVALID_BUFFER_SLOT) {
10168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return -EBUSY;
10268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
10368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    *buf = found;
10468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
10568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
10668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
10768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::queueBuffer(int buf) {
1087dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::queueBuffer");
10968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
11068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (buf < 0 || mBufferCount <= buf) {
11168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("queueBuffer: slot index out of range [0, %d]: %d",
11268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                mBufferCount, buf);
11368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return -EINVAL;
11468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    } else if (!mSlots[buf].mOwnedByClient) {
11568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("queueBuffer: slot %d is not owned by the client", buf);
11668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return -EINVAL;
11768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    } else if (mSlots[buf].mGraphicBuffer == 0) {
11868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
11968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                buf);
12068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return -EINVAL;
12168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
12268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mSlots[buf].mOwnedByClient = false;
12368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mLastQueued = buf;
12468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
12568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
12668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
12768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisvoid SurfaceTexture::cancelBuffer(int buf) {
1287dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::cancelBuffer");
12968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
13068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (buf < 0 || mBufferCount <= buf) {
13168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
13268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                buf);
13368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return;
13468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    } else if (!mSlots[buf].mOwnedByClient) {
13568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("cancelBuffer: slot %d is not owned by the client", buf);
13668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        return;
13768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
13868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    mSlots[buf].mOwnedByClient = false;
13968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
14068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
14168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::setCrop(const Rect& reg) {
1427dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::setCrop");
14368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
14468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    // XXX: How should we handle crops?
14568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
14668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
14768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
14868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::setTransform(uint32_t transform) {
1497dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::setTransform");
15068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
15168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    // XXX: How should we handle transforms?
15268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
15368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
15468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
15568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisstatus_t SurfaceTexture::updateTexImage() {
1567dc00d5eb27de41f93a7e232b3cd374c84eb77d1Jamie Gennis    LOGV("SurfaceTexture::updateTexImage");
15768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    Mutex::Autolock lock(mMutex);
15868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
15968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    // We always bind the texture even if we don't update its contents.
16068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
16168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
16268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
16368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    // so this check will fail until a buffer gets queued.
16468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (mCurrentTexture != mLastQueued) {
16568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        // XXX: Figure out the right target.
16668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        mCurrentTexture = mLastQueued;
16768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
16868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        if (image == EGL_NO_IMAGE_KHR) {
16968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            EGLDisplay dpy = eglGetCurrentDisplay();
17068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
17168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            image = createImage(dpy, graphicBuffer);
17268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[mCurrentTexture].mEglImage = image;
17368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[mCurrentTexture].mEglDisplay = dpy;
17468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        }
17568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
17668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        GLint error = glGetError();
17768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        if (error != GL_NO_ERROR) {
17868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            LOGE("error binding external texture image %p (slot %d): %#04x",
17968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                    image, mCurrentTexture, error);
18068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            return -EINVAL;
18168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        }
18268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
18368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return OK;
18468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
18568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
18668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennisvoid SurfaceTexture::freeAllBuffers() {
18768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
18868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        mSlots[i].mGraphicBuffer = 0;
18968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        mSlots[i].mOwnedByClient = false;
19068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
19168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
19268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
19368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
19468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        }
19568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
19668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
19768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
19868e4a7ac849b681b1fb769857fc04f64262480c4Jamie GennisEGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
19968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        const sp<GraphicBuffer>& graphicBuffer) {
20068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
20168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    EGLint attrs[] = {
20268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
20368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        EGL_NONE,
20468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    };
20568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
20668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
20768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    EGLint error = eglGetError();
20868e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    if (error != EGL_SUCCESS) {
20968e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("error creating EGLImage: %#x", error);
21068e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    } else if (image == EGL_NO_IMAGE_KHR) {
21168e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis        LOGE("no error reported, but no image was returned by "
21268e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis                "eglCreateImageKHR");
21368e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    }
21468e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis    return image;
21568e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}
21668e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis
21768e4a7ac849b681b1fb769857fc04f64262480c4Jamie Gennis}; // namespace android
218