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