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