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