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