OSDN Git Service

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