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