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