OSDN Git Service

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