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