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