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