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