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