OSDN Git Service

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