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