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