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