SurfaceTexture.cpp revision 79d01fe8232c67a18aeb8784c2b8783358ec4e44
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 "SurfaceTexture"
18//#define LOG_NDEBUG 0
19
20#define GL_GLEXT_PROTOTYPES
21#define EGL_EGLEXT_PROTOTYPES
22
23#include <EGL/egl.h>
24#include <EGL/eglext.h>
25#include <GLES2/gl2.h>
26#include <GLES2/gl2ext.h>
27
28#include <gui/SurfaceTexture.h>
29
30#include <surfaceflinger/ISurfaceComposer.h>
31#include <surfaceflinger/SurfaceComposerClient.h>
32#include <surfaceflinger/IGraphicBufferAlloc.h>
33
34#include <utils/Log.h>
35
36namespace android {
37
38// Transform matrices
39static float mtxIdentity[16] = {
40    1, 0, 0, 0,
41    0, 1, 0, 0,
42    0, 0, 1, 0,
43    0, 0, 0, 1,
44};
45static float mtxFlipH[16] = {
46    -1, 0, 0, 0,
47    0, 1, 0, 0,
48    0, 0, 1, 0,
49    1, 0, 0, 1,
50};
51static float mtxFlipV[16] = {
52    1, 0, 0, 0,
53    0, -1, 0, 0,
54    0, 0, 1, 0,
55    0, 1, 0, 1,
56};
57static float mtxRot90[16] = {
58    0, 1, 0, 0,
59    -1, 0, 0, 0,
60    0, 0, 1, 0,
61    1, 0, 0, 1,
62};
63static float mtxRot180[16] = {
64    -1, 0, 0, 0,
65    0, -1, 0, 0,
66    0, 0, 1, 0,
67    1, 1, 0, 1,
68};
69static float mtxRot270[16] = {
70    0, -1, 0, 0,
71    1, 0, 0, 0,
72    0, 0, 1, 0,
73    0, 1, 0, 1,
74};
75
76static void mtxMul(float out[16], const float a[16], const float b[16]);
77
78SurfaceTexture::SurfaceTexture(GLuint tex) :
79    mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
80    mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
81    LOGV("SurfaceTexture::SurfaceTexture");
82    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
83        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
84        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
85        mSlots[i].mOwnedByClient = false;
86    }
87    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
88    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
89}
90
91SurfaceTexture::~SurfaceTexture() {
92    LOGV("SurfaceTexture::~SurfaceTexture");
93    freeAllBuffers();
94}
95
96status_t SurfaceTexture::setBufferCount(int bufferCount) {
97    LOGV("SurfaceTexture::setBufferCount");
98    Mutex::Autolock lock(mMutex);
99    freeAllBuffers();
100    mBufferCount = bufferCount;
101    mCurrentTexture = INVALID_BUFFER_SLOT;
102    mLastQueued = INVALID_BUFFER_SLOT;
103    return OK;
104}
105
106sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
107        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
108    LOGV("SurfaceTexture::requestBuffer");
109    Mutex::Autolock lock(mMutex);
110    if (buf < 0 || mBufferCount <= buf) {
111        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
112                mBufferCount, buf);
113        return 0;
114    }
115    usage |= GraphicBuffer::USAGE_HW_TEXTURE;
116    sp<GraphicBuffer> graphicBuffer(
117            mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage));
118    if (graphicBuffer == 0) {
119        LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
120    } else {
121        mSlots[buf].mGraphicBuffer = graphicBuffer;
122        if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
123            eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
124            mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
125            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
126        }
127        mAllocdBuffers.add(graphicBuffer);
128    }
129    return graphicBuffer;
130}
131
132status_t SurfaceTexture::dequeueBuffer(int *buf) {
133    LOGV("SurfaceTexture::dequeueBuffer");
134    Mutex::Autolock lock(mMutex);
135    int found = INVALID_BUFFER_SLOT;
136    for (int i = 0; i < mBufferCount; i++) {
137        if (!mSlots[i].mOwnedByClient && i != mCurrentTexture && i != mLastQueued) {
138            mSlots[i].mOwnedByClient = true;
139            found = i;
140            break;
141        }
142    }
143    if (found == INVALID_BUFFER_SLOT) {
144        return -EBUSY;
145    }
146    *buf = found;
147    return OK;
148}
149
150status_t SurfaceTexture::queueBuffer(int buf) {
151    LOGV("SurfaceTexture::queueBuffer");
152    Mutex::Autolock lock(mMutex);
153    if (buf < 0 || mBufferCount <= buf) {
154        LOGE("queueBuffer: slot index out of range [0, %d]: %d",
155                mBufferCount, buf);
156        return -EINVAL;
157    } else if (!mSlots[buf].mOwnedByClient) {
158        LOGE("queueBuffer: slot %d is not owned by the client", buf);
159        return -EINVAL;
160    } else if (mSlots[buf].mGraphicBuffer == 0) {
161        LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
162                buf);
163        return -EINVAL;
164    }
165    mSlots[buf].mOwnedByClient = false;
166    mLastQueued = buf;
167    mLastQueuedCrop = mNextCrop;
168    mLastQueuedTransform = mNextTransform;
169    if (mFrameAvailableListener != 0) {
170        mFrameAvailableListener->onFrameAvailable();
171    }
172    return OK;
173}
174
175void SurfaceTexture::cancelBuffer(int buf) {
176    LOGV("SurfaceTexture::cancelBuffer");
177    Mutex::Autolock lock(mMutex);
178    if (buf < 0 || mBufferCount <= buf) {
179        LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
180                buf);
181        return;
182    } else if (!mSlots[buf].mOwnedByClient) {
183        LOGE("cancelBuffer: slot %d is not owned by the client", buf);
184        return;
185    }
186    mSlots[buf].mOwnedByClient = false;
187}
188
189status_t SurfaceTexture::setCrop(const Rect& crop) {
190    LOGV("SurfaceTexture::setCrop");
191    Mutex::Autolock lock(mMutex);
192    mNextCrop = crop;
193    return OK;
194}
195
196status_t SurfaceTexture::setTransform(uint32_t transform) {
197    LOGV("SurfaceTexture::setTransform");
198    Mutex::Autolock lock(mMutex);
199    mNextTransform = transform;
200    return OK;
201}
202
203status_t SurfaceTexture::updateTexImage() {
204    LOGV("SurfaceTexture::updateTexImage");
205    Mutex::Autolock lock(mMutex);
206
207    // We always bind the texture even if we don't update its contents.
208    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
209
210    // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
211    // so this check will fail until a buffer gets queued.
212    if (mCurrentTexture != mLastQueued) {
213        // Update the GL texture object.
214        EGLImageKHR image = mSlots[mLastQueued].mEglImage;
215        if (image == EGL_NO_IMAGE_KHR) {
216            EGLDisplay dpy = eglGetCurrentDisplay();
217            sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer;
218            image = createImage(dpy, graphicBuffer);
219            mSlots[mLastQueued].mEglImage = image;
220            mSlots[mLastQueued].mEglDisplay = dpy;
221        }
222
223        GLint error;
224        while ((error = glGetError()) != GL_NO_ERROR) {
225            LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
226        }
227        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
228        bool failed = false;
229        while ((error = glGetError()) != GL_NO_ERROR) {
230            LOGE("error binding external texture image %p (slot %d): %#04x",
231                    image, mLastQueued, error);
232            failed = true;
233        }
234        if (failed) {
235            return -EINVAL;
236        }
237
238        // Update the SurfaceTexture state.
239        mCurrentTexture = mLastQueued;
240        mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
241        mCurrentCrop = mLastQueuedCrop;
242        mCurrentTransform = mLastQueuedTransform;
243    }
244    return OK;
245}
246
247void SurfaceTexture::getTransformMatrix(float mtx[16]) {
248    LOGV("SurfaceTexture::updateTexImage");
249    Mutex::Autolock lock(mMutex);
250
251    float xform[16];
252    for (int i = 0; i < 16; i++) {
253        xform[i] = mtxIdentity[i];
254    }
255    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
256        float result[16];
257        mtxMul(result, xform, mtxFlipH);
258        for (int i = 0; i < 16; i++) {
259            xform[i] = result[i];
260        }
261    }
262    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
263        float result[16];
264        mtxMul(result, xform, mtxFlipV);
265        for (int i = 0; i < 16; i++) {
266            xform[i] = result[i];
267        }
268    }
269    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
270        float result[16];
271        mtxMul(result, xform, mtxRot90);
272        for (int i = 0; i < 16; i++) {
273            xform[i] = result[i];
274        }
275    }
276
277    sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
278    float tx, ty, sx, sy;
279    if (!mCurrentCrop.isEmpty()) {
280        tx = float(mCurrentCrop.left) / float(buf->getWidth());
281        ty = float(buf->getHeight() - mCurrentCrop.bottom) /
282                float(buf->getHeight());
283        sx = float(mCurrentCrop.width()) / float(buf->getWidth());
284        sy = float(mCurrentCrop.height()) / float(buf->getHeight());
285    } else {
286        tx = 0.0f;
287        ty = 0.0f;
288        sx = 1.0f;
289        sy = 1.0f;
290    }
291    float crop[16] = {
292        sx, 0, 0, 0,
293        0, sy, 0, 0,
294        0, 0, 1, 0,
295        sx*tx, sy*ty, 0, 1,
296    };
297
298    float mtxBeforeFlipV[16];
299    mtxMul(mtxBeforeFlipV, crop, xform);
300
301    // SurfaceFlinger expects the top of its window textures to be at a Y
302    // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
303    // want to expose this to applications, however, so we must add an
304    // additional vertical flip to the transform after all the other transforms.
305    mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
306}
307
308void SurfaceTexture::setFrameAvailableListener(
309        const sp<FrameAvailableListener>& l) {
310    LOGV("SurfaceTexture::setFrameAvailableListener");
311    Mutex::Autolock lock(mMutex);
312    mFrameAvailableListener = l;
313}
314
315void SurfaceTexture::freeAllBuffers() {
316    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
317        mSlots[i].mGraphicBuffer = 0;
318        mSlots[i].mOwnedByClient = false;
319        if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
320            eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
321            mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
322            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
323        }
324    }
325
326    int exceptBuf = -1;
327    for (size_t i = 0; i < mAllocdBuffers.size(); i++) {
328        if (mAllocdBuffers[i] == mCurrentTextureBuf) {
329            exceptBuf = i;
330            break;
331        }
332    }
333    mAllocdBuffers.clear();
334    if (exceptBuf >= 0) {
335        mAllocdBuffers.add(mCurrentTextureBuf);
336    }
337    mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);
338}
339
340EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
341        const sp<GraphicBuffer>& graphicBuffer) {
342    EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
343    EGLint attrs[] = {
344        EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
345        EGL_NONE,
346    };
347    EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
348            EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
349    EGLint error = eglGetError();
350    if (error != EGL_SUCCESS) {
351        LOGE("error creating EGLImage: %#x", error);
352    } else if (image == EGL_NO_IMAGE_KHR) {
353        LOGE("no error reported, but no image was returned by "
354                "eglCreateImageKHR");
355    }
356    return image;
357}
358
359static void mtxMul(float out[16], const float a[16], const float b[16]) {
360    out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
361    out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
362    out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
363    out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
364
365    out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
366    out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
367    out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
368    out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
369
370    out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
371    out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
372    out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
373    out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
374
375    out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
376    out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
377    out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
378    out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
379}
380
381}; // namespace android
382