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