• 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 #include <cutils/compiler.h>
29 
30 #include <hardware/hardware.h>
31 
32 #include <gui/BufferItem.h>
33 #include <gui/GLConsumer.h>
34 #include <gui/IGraphicBufferAlloc.h>
35 #include <gui/ISurfaceComposer.h>
36 #include <gui/SurfaceComposerClient.h>
37 
38 #include <private/gui/ComposerService.h>
39 #include <private/gui/SyncFeatures.h>
40 
41 #include <utils/Log.h>
42 #include <utils/String8.h>
43 #include <utils/Trace.h>
44 
45 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
46 #define CROP_EXT_STR "EGL_ANDROID_image_crop"
47 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
48 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
49 
50 namespace android {
51 
52 // Macros for including the GLConsumer name in log messages
53 #define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
54 #define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
55 //#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
56 #define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
57 #define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
58 
59 static const struct {
60     uint32_t width, height;
61     char const* bits;
62 } kDebugData = { 15, 12,
63     "_______________"
64     "_______________"
65     "_____XX_XX_____"
66     "__X_X_____X_X__"
67     "__X_XXXXXXX_X__"
68     "__XXXXXXXXXXX__"
69     "___XX_XXX_XX___"
70     "____XXXXXXX____"
71     "_____X___X_____"
72     "____X_____X____"
73     "_______________"
74     "_______________"
75 };
76 
77 // Transform matrices
78 static float mtxIdentity[16] = {
79     1, 0, 0, 0,
80     0, 1, 0, 0,
81     0, 0, 1, 0,
82     0, 0, 0, 1,
83 };
84 static float mtxFlipH[16] = {
85     -1, 0, 0, 0,
86     0, 1, 0, 0,
87     0, 0, 1, 0,
88     1, 0, 0, 1,
89 };
90 static float mtxFlipV[16] = {
91     1, 0, 0, 0,
92     0, -1, 0, 0,
93     0, 0, 1, 0,
94     0, 1, 0, 1,
95 };
96 static float mtxRot90[16] = {
97     0, 1, 0, 0,
98     -1, 0, 0, 0,
99     0, 0, 1, 0,
100     1, 0, 0, 1,
101 };
102 
103 static void mtxMul(float out[16], const float a[16], const float b[16]);
104 
105 Mutex GLConsumer::sStaticInitLock;
106 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
107 
hasEglAndroidImageCropImpl()108 static bool hasEglAndroidImageCropImpl() {
109     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
110     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
111     size_t cropExtLen = strlen(CROP_EXT_STR);
112     size_t extsLen = strlen(exts);
113     bool equal = !strcmp(CROP_EXT_STR, exts);
114     bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
115     bool atEnd = (cropExtLen+1) < extsLen &&
116             !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
117     bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
118     return equal || atStart || atEnd || inMiddle;
119 }
120 
hasEglAndroidImageCrop()121 static bool hasEglAndroidImageCrop() {
122     // Only compute whether the extension is present once the first time this
123     // function is called.
124     static bool hasIt = hasEglAndroidImageCropImpl();
125     return hasIt;
126 }
127 
hasEglProtectedContentImpl()128 static bool hasEglProtectedContentImpl() {
129     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
130     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
131     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
132     size_t extsLen = strlen(exts);
133     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
134     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
135     bool atEnd = (cropExtLen+1) < extsLen &&
136             !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen+1));
137     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
138     return equal || atStart || atEnd || inMiddle;
139 }
140 
hasEglProtectedContent()141 static bool hasEglProtectedContent() {
142     // Only compute whether the extension is present once the first time this
143     // function is called.
144     static bool hasIt = hasEglProtectedContentImpl();
145     return hasIt;
146 }
147 
isEglImageCroppable(const Rect & crop)148 static bool isEglImageCroppable(const Rect& crop) {
149     return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
150 }
151 
GLConsumer(const sp<IGraphicBufferConsumer> & bq,uint32_t tex,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)152 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
153         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
154     ConsumerBase(bq, isControlledByApp),
155     mCurrentCrop(Rect::EMPTY_RECT),
156     mCurrentTransform(0),
157     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
158     mCurrentFence(Fence::NO_FENCE),
159     mCurrentTimestamp(0),
160     mCurrentFrameNumber(0),
161     mDefaultWidth(1),
162     mDefaultHeight(1),
163     mFilteringEnabled(true),
164     mTexName(tex),
165     mUseFenceSync(useFenceSync),
166     mTexTarget(texTarget),
167     mEglDisplay(EGL_NO_DISPLAY),
168     mEglContext(EGL_NO_CONTEXT),
169     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
170     mAttached(true)
171 {
172     GLC_LOGV("GLConsumer");
173 
174     memcpy(mCurrentTransformMatrix, mtxIdentity,
175             sizeof(mCurrentTransformMatrix));
176 
177     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
178 }
179 
GLConsumer(const sp<IGraphicBufferConsumer> & bq,uint32_t texTarget,bool useFenceSync,bool isControlledByApp)180 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
181         bool useFenceSync, bool isControlledByApp) :
182     ConsumerBase(bq, isControlledByApp),
183     mCurrentCrop(Rect::EMPTY_RECT),
184     mCurrentTransform(0),
185     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
186     mCurrentFence(Fence::NO_FENCE),
187     mCurrentTimestamp(0),
188     mCurrentFrameNumber(0),
189     mDefaultWidth(1),
190     mDefaultHeight(1),
191     mFilteringEnabled(true),
192     mTexName(0),
193     mUseFenceSync(useFenceSync),
194     mTexTarget(texTarget),
195     mEglDisplay(EGL_NO_DISPLAY),
196     mEglContext(EGL_NO_CONTEXT),
197     mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
198     mAttached(false)
199 {
200     GLC_LOGV("GLConsumer");
201 
202     memcpy(mCurrentTransformMatrix, mtxIdentity,
203             sizeof(mCurrentTransformMatrix));
204 
205     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
206 }
207 
setDefaultBufferSize(uint32_t w,uint32_t h)208 status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
209 {
210     Mutex::Autolock lock(mMutex);
211     if (mAbandoned) {
212         GLC_LOGE("setDefaultBufferSize: GLConsumer is abandoned!");
213         return NO_INIT;
214     }
215     mDefaultWidth = w;
216     mDefaultHeight = h;
217     return mConsumer->setDefaultBufferSize(w, h);
218 }
219 
updateTexImage()220 status_t GLConsumer::updateTexImage() {
221     ATRACE_CALL();
222     GLC_LOGV("updateTexImage");
223     Mutex::Autolock lock(mMutex);
224 
225     if (mAbandoned) {
226         GLC_LOGE("updateTexImage: GLConsumer is abandoned!");
227         return NO_INIT;
228     }
229 
230     // Make sure the EGL state is the same as in previous calls.
231     status_t err = checkAndUpdateEglStateLocked();
232     if (err != NO_ERROR) {
233         return err;
234     }
235 
236     BufferItem item;
237 
238     // Acquire the next buffer.
239     // In asynchronous mode the list is guaranteed to be one buffer
240     // deep, while in synchronous mode we use the oldest buffer.
241     err = acquireBufferLocked(&item, 0);
242     if (err != NO_ERROR) {
243         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
244             // We always bind the texture even if we don't update its contents.
245             GLC_LOGV("updateTexImage: no buffers were available");
246             glBindTexture(mTexTarget, mTexName);
247             err = NO_ERROR;
248         } else {
249             GLC_LOGE("updateTexImage: acquire failed: %s (%d)",
250                 strerror(-err), err);
251         }
252         return err;
253     }
254 
255     // Release the previous buffer.
256     err = updateAndReleaseLocked(item);
257     if (err != NO_ERROR) {
258         // We always bind the texture.
259         glBindTexture(mTexTarget, mTexName);
260         return err;
261     }
262 
263     // Bind the new buffer to the GL texture, and wait until it's ready.
264     return bindTextureImageLocked();
265 }
266 
267 
releaseTexImage()268 status_t GLConsumer::releaseTexImage() {
269     ATRACE_CALL();
270     GLC_LOGV("releaseTexImage");
271     Mutex::Autolock lock(mMutex);
272 
273     if (mAbandoned) {
274         GLC_LOGE("releaseTexImage: GLConsumer is abandoned!");
275         return NO_INIT;
276     }
277 
278     // Make sure the EGL state is the same as in previous calls.
279     status_t err = NO_ERROR;
280 
281     if (mAttached) {
282         err = checkAndUpdateEglStateLocked(true);
283         if (err != NO_ERROR) {
284             return err;
285         }
286     } else {
287         // if we're detached, no need to validate EGL's state -- we won't use it.
288     }
289 
290     // Update the GLConsumer state.
291     int buf = mCurrentTexture;
292     if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
293 
294         GLC_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached);
295 
296         if (mAttached) {
297             // Do whatever sync ops we need to do before releasing the slot.
298             err = syncForReleaseLocked(mEglDisplay);
299             if (err != NO_ERROR) {
300                 GLC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
301                 return err;
302             }
303         } else {
304             // if we're detached, we just use the fence that was created in detachFromContext()
305             // so... basically, nothing more to do here.
306         }
307 
308         err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
309         if (err < NO_ERROR) {
310             GLC_LOGE("releaseTexImage: failed to release buffer: %s (%d)",
311                     strerror(-err), err);
312             return err;
313         }
314 
315         if (mReleasedTexImage == NULL) {
316             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
317         }
318 
319         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
320         mCurrentTextureImage = mReleasedTexImage;
321         mCurrentCrop.makeInvalid();
322         mCurrentTransform = 0;
323         mCurrentTimestamp = 0;
324         mCurrentFence = Fence::NO_FENCE;
325 
326         if (mAttached) {
327             // This binds a dummy buffer (mReleasedTexImage).
328             status_t result = bindTextureImageLocked();
329             if (result != NO_ERROR) {
330                 return result;
331             }
332         } else {
333             // detached, don't touch the texture (and we may not even have an
334             // EGLDisplay here.
335         }
336     }
337 
338     return NO_ERROR;
339 }
340 
getDebugTexImageBuffer()341 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
342     Mutex::Autolock _l(sStaticInitLock);
343     if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
344         // The first time, create the debug texture in case the application
345         // continues to use it.
346         sp<GraphicBuffer> buffer = new GraphicBuffer(
347                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
348                 GraphicBuffer::USAGE_SW_WRITE_RARELY,
349                 "[GLConsumer debug texture]");
350         uint32_t* bits;
351         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
352         uint32_t stride = buffer->getStride();
353         uint32_t height = buffer->getHeight();
354         memset(bits, 0, stride * height * 4);
355         for (uint32_t y = 0; y < kDebugData.height; y++) {
356             for (uint32_t x = 0; x < kDebugData.width; x++) {
357                 bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ?
358                     0xFF000000 : 0xFFFFFFFF;
359             }
360             bits += stride;
361         }
362         buffer->unlock();
363         sReleasedTexImageBuffer = buffer;
364     }
365     return sReleasedTexImageBuffer;
366 }
367 
acquireBufferLocked(BufferItem * item,nsecs_t presentWhen,uint64_t maxFrameNumber)368 status_t GLConsumer::acquireBufferLocked(BufferItem *item,
369         nsecs_t presentWhen, uint64_t maxFrameNumber) {
370     status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
371             maxFrameNumber);
372     if (err != NO_ERROR) {
373         return err;
374     }
375 
376     // If item->mGraphicBuffer is not null, this buffer has not been acquired
377     // before, so any prior EglImage created is using a stale buffer. This
378     // replaces any old EglImage with a new one (using the new buffer).
379     if (item->mGraphicBuffer != NULL) {
380         int slot = item->mSlot;
381         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
382     }
383 
384     return NO_ERROR;
385 }
386 
releaseBufferLocked(int buf,sp<GraphicBuffer> graphicBuffer,EGLDisplay display,EGLSyncKHR eglFence)387 status_t GLConsumer::releaseBufferLocked(int buf,
388         sp<GraphicBuffer> graphicBuffer,
389         EGLDisplay display, EGLSyncKHR eglFence) {
390     // release the buffer if it hasn't already been discarded by the
391     // BufferQueue. This can happen, for example, when the producer of this
392     // buffer has reallocated the original buffer slot after this buffer
393     // was acquired.
394     status_t err = ConsumerBase::releaseBufferLocked(
395             buf, graphicBuffer, display, eglFence);
396     mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
397     return err;
398 }
399 
updateAndReleaseLocked(const BufferItem & item,PendingRelease * pendingRelease)400 status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
401         PendingRelease* pendingRelease)
402 {
403     status_t err = NO_ERROR;
404 
405     int slot = item.mSlot;
406 
407     if (!mAttached) {
408         GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
409                 "ES context");
410         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
411                 mEglDisplay, EGL_NO_SYNC_KHR);
412         return INVALID_OPERATION;
413     }
414 
415     // Confirm state.
416     err = checkAndUpdateEglStateLocked();
417     if (err != NO_ERROR) {
418         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
419                 mEglDisplay, EGL_NO_SYNC_KHR);
420         return err;
421     }
422 
423     // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
424     // if nessessary, for the gralloc buffer currently in the slot in
425     // ConsumerBase.
426     // We may have to do this even when item.mGraphicBuffer == NULL (which
427     // means the buffer was previously acquired).
428     err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
429     if (err != NO_ERROR) {
430         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
431                 mEglDisplay, slot);
432         releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
433                 mEglDisplay, EGL_NO_SYNC_KHR);
434         return UNKNOWN_ERROR;
435     }
436 
437     // Do whatever sync ops we need to do before releasing the old slot.
438     if (slot != mCurrentTexture) {
439         err = syncForReleaseLocked(mEglDisplay);
440         if (err != NO_ERROR) {
441             // Release the buffer we just acquired.  It's not safe to
442             // release the old buffer, so instead we just drop the new frame.
443             // As we are still under lock since acquireBuffer, it is safe to
444             // release by slot.
445             releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
446                     mEglDisplay, EGL_NO_SYNC_KHR);
447             return err;
448         }
449     }
450 
451     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
452             mCurrentTexture, mCurrentTextureImage != NULL ?
453                     mCurrentTextureImage->graphicBufferHandle() : 0,
454             slot, mSlots[slot].mGraphicBuffer->handle);
455 
456     // Hang onto the pointer so that it isn't freed in the call to
457     // releaseBufferLocked() if we're in shared buffer mode and both buffers are
458     // the same.
459     sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
460 
461     // release old buffer
462     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
463         if (pendingRelease == nullptr) {
464             status_t status = releaseBufferLocked(
465                     mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
466                     mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
467             if (status < NO_ERROR) {
468                 GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
469                         strerror(-status), status);
470                 err = status;
471                 // keep going, with error raised [?]
472             }
473         } else {
474             pendingRelease->currentTexture = mCurrentTexture;
475             pendingRelease->graphicBuffer =
476                     mCurrentTextureImage->graphicBuffer();
477             pendingRelease->display = mEglDisplay;
478             pendingRelease->fence = mEglSlots[mCurrentTexture].mEglFence;
479             pendingRelease->isPending = true;
480         }
481     }
482 
483     // Update the GLConsumer state.
484     mCurrentTexture = slot;
485     mCurrentTextureImage = nextTextureImage;
486     mCurrentCrop = item.mCrop;
487     mCurrentTransform = item.mTransform;
488     mCurrentScalingMode = item.mScalingMode;
489     mCurrentTimestamp = item.mTimestamp;
490     mCurrentFence = item.mFence;
491     mCurrentFrameNumber = item.mFrameNumber;
492 
493     computeCurrentTransformMatrixLocked();
494 
495     return err;
496 }
497 
bindTextureImageLocked()498 status_t GLConsumer::bindTextureImageLocked() {
499     if (mEglDisplay == EGL_NO_DISPLAY) {
500         ALOGE("bindTextureImage: invalid display");
501         return INVALID_OPERATION;
502     }
503 
504     GLenum error;
505     while ((error = glGetError()) != GL_NO_ERROR) {
506         GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
507     }
508 
509     glBindTexture(mTexTarget, mTexName);
510     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
511             mCurrentTextureImage == NULL) {
512         GLC_LOGE("bindTextureImage: no currently-bound texture");
513         return NO_INIT;
514     }
515 
516     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
517                                                         mCurrentCrop);
518     if (err != NO_ERROR) {
519         GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
520                 mEglDisplay, mCurrentTexture);
521         return UNKNOWN_ERROR;
522     }
523     mCurrentTextureImage->bindToTextureTarget(mTexTarget);
524 
525     // In the rare case that the display is terminated and then initialized
526     // again, we can't detect that the display changed (it didn't), but the
527     // image is invalid. In this case, repeat the exact same steps while
528     // forcing the creation of a new image.
529     if ((error = glGetError()) != GL_NO_ERROR) {
530         glBindTexture(mTexTarget, mTexName);
531         status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
532                                                                mCurrentCrop,
533                                                                true);
534         if (result != NO_ERROR) {
535             GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
536                     mEglDisplay, mCurrentTexture);
537             return UNKNOWN_ERROR;
538         }
539         mCurrentTextureImage->bindToTextureTarget(mTexTarget);
540         if ((error = glGetError()) != GL_NO_ERROR) {
541             GLC_LOGE("bindTextureImage: error binding external image: %#04x", error);
542             return UNKNOWN_ERROR;
543         }
544     }
545 
546     // Wait for the new buffer to be ready.
547     return doGLFenceWaitLocked();
548 }
549 
checkAndUpdateEglStateLocked(bool contextCheck)550 status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
551     EGLDisplay dpy = eglGetCurrentDisplay();
552     EGLContext ctx = eglGetCurrentContext();
553 
554     if (!contextCheck) {
555         // if this is the first time we're called, mEglDisplay/mEglContext have
556         // never been set, so don't error out (below).
557         if (mEglDisplay == EGL_NO_DISPLAY) {
558             mEglDisplay = dpy;
559         }
560         if (mEglContext == EGL_NO_CONTEXT) {
561             mEglContext = ctx;
562         }
563     }
564 
565     if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
566         GLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
567         return INVALID_OPERATION;
568     }
569 
570     if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
571         GLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
572         return INVALID_OPERATION;
573     }
574 
575     mEglDisplay = dpy;
576     mEglContext = ctx;
577     return NO_ERROR;
578 }
579 
setReleaseFence(const sp<Fence> & fence)580 void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
581     if (fence->isValid() &&
582             mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
583         status_t err = addReleaseFence(mCurrentTexture,
584                 mCurrentTextureImage->graphicBuffer(), fence);
585         if (err != OK) {
586             GLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
587                     strerror(-err), err);
588         }
589     }
590 }
591 
detachFromContext()592 status_t GLConsumer::detachFromContext() {
593     ATRACE_CALL();
594     GLC_LOGV("detachFromContext");
595     Mutex::Autolock lock(mMutex);
596 
597     if (mAbandoned) {
598         GLC_LOGE("detachFromContext: abandoned GLConsumer");
599         return NO_INIT;
600     }
601 
602     if (!mAttached) {
603         GLC_LOGE("detachFromContext: GLConsumer is not attached to a "
604                 "context");
605         return INVALID_OPERATION;
606     }
607 
608     EGLDisplay dpy = eglGetCurrentDisplay();
609     EGLContext ctx = eglGetCurrentContext();
610 
611     if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
612         GLC_LOGE("detachFromContext: invalid current EGLDisplay");
613         return INVALID_OPERATION;
614     }
615 
616     if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
617         GLC_LOGE("detachFromContext: invalid current EGLContext");
618         return INVALID_OPERATION;
619     }
620 
621     if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
622         status_t err = syncForReleaseLocked(dpy);
623         if (err != OK) {
624             return err;
625         }
626 
627         glDeleteTextures(1, &mTexName);
628     }
629 
630     mEglDisplay = EGL_NO_DISPLAY;
631     mEglContext = EGL_NO_CONTEXT;
632     mAttached = false;
633 
634     return OK;
635 }
636 
attachToContext(uint32_t tex)637 status_t GLConsumer::attachToContext(uint32_t tex) {
638     ATRACE_CALL();
639     GLC_LOGV("attachToContext");
640     Mutex::Autolock lock(mMutex);
641 
642     if (mAbandoned) {
643         GLC_LOGE("attachToContext: abandoned GLConsumer");
644         return NO_INIT;
645     }
646 
647     if (mAttached) {
648         GLC_LOGE("attachToContext: GLConsumer is already attached to a "
649                 "context");
650         return INVALID_OPERATION;
651     }
652 
653     EGLDisplay dpy = eglGetCurrentDisplay();
654     EGLContext ctx = eglGetCurrentContext();
655 
656     if (dpy == EGL_NO_DISPLAY) {
657         GLC_LOGE("attachToContext: invalid current EGLDisplay");
658         return INVALID_OPERATION;
659     }
660 
661     if (ctx == EGL_NO_CONTEXT) {
662         GLC_LOGE("attachToContext: invalid current EGLContext");
663         return INVALID_OPERATION;
664     }
665 
666     // We need to bind the texture regardless of whether there's a current
667     // buffer.
668     glBindTexture(mTexTarget, GLuint(tex));
669 
670     mEglDisplay = dpy;
671     mEglContext = ctx;
672     mTexName = tex;
673     mAttached = true;
674 
675     if (mCurrentTextureImage != NULL) {
676         // This may wait for a buffer a second time. This is likely required if
677         // this is a different context, since otherwise the wait could be skipped
678         // by bouncing through another context. For the same context the extra
679         // wait is redundant.
680         status_t err =  bindTextureImageLocked();
681         if (err != NO_ERROR) {
682             return err;
683         }
684     }
685 
686     return OK;
687 }
688 
689 
syncForReleaseLocked(EGLDisplay dpy)690 status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
691     GLC_LOGV("syncForReleaseLocked");
692 
693     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
694         if (SyncFeatures::getInstance().useNativeFenceSync()) {
695             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
696                     EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
697             if (sync == EGL_NO_SYNC_KHR) {
698                 GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
699                         eglGetError());
700                 return UNKNOWN_ERROR;
701             }
702             glFlush();
703             int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
704             eglDestroySyncKHR(dpy, sync);
705             if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
706                 GLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
707                         "fd: %#x", eglGetError());
708                 return UNKNOWN_ERROR;
709             }
710             sp<Fence> fence(new Fence(fenceFd));
711             status_t err = addReleaseFenceLocked(mCurrentTexture,
712                     mCurrentTextureImage->graphicBuffer(), fence);
713             if (err != OK) {
714                 GLC_LOGE("syncForReleaseLocked: error adding release fence: "
715                         "%s (%d)", strerror(-err), err);
716                 return err;
717             }
718         } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
719             EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
720             if (fence != EGL_NO_SYNC_KHR) {
721                 // There is already a fence for the current slot.  We need to
722                 // wait on that before replacing it with another fence to
723                 // ensure that all outstanding buffer accesses have completed
724                 // before the producer accesses it.
725                 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
726                 if (result == EGL_FALSE) {
727                     GLC_LOGE("syncForReleaseLocked: error waiting for previous "
728                             "fence: %#x", eglGetError());
729                     return UNKNOWN_ERROR;
730                 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
731                     GLC_LOGE("syncForReleaseLocked: timeout waiting for previous "
732                             "fence");
733                     return TIMED_OUT;
734                 }
735                 eglDestroySyncKHR(dpy, fence);
736             }
737 
738             // Create a fence for the outstanding accesses in the current
739             // OpenGL ES context.
740             fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
741             if (fence == EGL_NO_SYNC_KHR) {
742                 GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
743                         eglGetError());
744                 return UNKNOWN_ERROR;
745             }
746             glFlush();
747             mEglSlots[mCurrentTexture].mEglFence = fence;
748         }
749     }
750 
751     return OK;
752 }
753 
isExternalFormat(PixelFormat format)754 bool GLConsumer::isExternalFormat(PixelFormat format)
755 {
756     switch (format) {
757     // supported YUV formats
758     case HAL_PIXEL_FORMAT_YV12:
759     // Legacy/deprecated YUV formats
760     case HAL_PIXEL_FORMAT_YCbCr_422_SP:
761     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
762     case HAL_PIXEL_FORMAT_YCbCr_422_I:
763         return true;
764     }
765 
766     // Any OEM format needs to be considered
767     if (format>=0x100 && format<=0x1FF)
768         return true;
769 
770     return false;
771 }
772 
getCurrentTextureTarget() const773 uint32_t GLConsumer::getCurrentTextureTarget() const {
774     return mTexTarget;
775 }
776 
getTransformMatrix(float mtx[16])777 void GLConsumer::getTransformMatrix(float mtx[16]) {
778     Mutex::Autolock lock(mMutex);
779     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
780 }
781 
setFilteringEnabled(bool enabled)782 void GLConsumer::setFilteringEnabled(bool enabled) {
783     Mutex::Autolock lock(mMutex);
784     if (mAbandoned) {
785         GLC_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
786         return;
787     }
788     bool needsRecompute = mFilteringEnabled != enabled;
789     mFilteringEnabled = enabled;
790 
791     if (needsRecompute && mCurrentTextureImage==NULL) {
792         GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
793     }
794 
795     if (needsRecompute && mCurrentTextureImage != NULL) {
796         computeCurrentTransformMatrixLocked();
797     }
798 }
799 
computeCurrentTransformMatrixLocked()800 void GLConsumer::computeCurrentTransformMatrixLocked() {
801     GLC_LOGV("computeCurrentTransformMatrixLocked");
802     sp<GraphicBuffer> buf = (mCurrentTextureImage == nullptr) ?
803             nullptr : mCurrentTextureImage->graphicBuffer();
804     if (buf == nullptr) {
805         GLC_LOGD("computeCurrentTransformMatrixLocked: "
806                 "mCurrentTextureImage is NULL");
807     }
808     computeTransformMatrix(mCurrentTransformMatrix, buf,
809         isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
810         mCurrentTransform, mFilteringEnabled);
811 }
812 
computeTransformMatrix(float outTransform[16],const sp<GraphicBuffer> & buf,const Rect & cropRect,uint32_t transform,bool filtering)813 void GLConsumer::computeTransformMatrix(float outTransform[16],
814         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
815         bool filtering) {
816 
817     float xform[16];
818     for (int i = 0; i < 16; i++) {
819         xform[i] = mtxIdentity[i];
820     }
821     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
822         float result[16];
823         mtxMul(result, xform, mtxFlipH);
824         for (int i = 0; i < 16; i++) {
825             xform[i] = result[i];
826         }
827     }
828     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
829         float result[16];
830         mtxMul(result, xform, mtxFlipV);
831         for (int i = 0; i < 16; i++) {
832             xform[i] = result[i];
833         }
834     }
835     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
836         float result[16];
837         mtxMul(result, xform, mtxRot90);
838         for (int i = 0; i < 16; i++) {
839             xform[i] = result[i];
840         }
841     }
842 
843     float mtxBeforeFlipV[16];
844     if (!cropRect.isEmpty()) {
845         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
846         float bufferWidth = buf->getWidth();
847         float bufferHeight = buf->getHeight();
848         float shrinkAmount = 0.0f;
849         if (filtering) {
850             // In order to prevent bilinear sampling beyond the edge of the
851             // crop rectangle we may need to shrink it by 2 texels in each
852             // dimension.  Normally this would just need to take 1/2 a texel
853             // off each end, but because the chroma channels of YUV420 images
854             // are subsampled we may need to shrink the crop region by a whole
855             // texel on each side.
856             switch (buf->getPixelFormat()) {
857                 case PIXEL_FORMAT_RGBA_8888:
858                 case PIXEL_FORMAT_RGBX_8888:
859                 case PIXEL_FORMAT_RGB_888:
860                 case PIXEL_FORMAT_RGB_565:
861                 case PIXEL_FORMAT_BGRA_8888:
862                     // We know there's no subsampling of any channels, so we
863                     // only need to shrink by a half a pixel.
864                     shrinkAmount = 0.5;
865                     break;
866 
867                 default:
868                     // If we don't recognize the format, we must assume the
869                     // worst case (that we care about), which is YUV420.
870                     shrinkAmount = 1.0;
871                     break;
872             }
873         }
874 
875         // Only shrink the dimensions that are not the size of the buffer.
876         if (cropRect.width() < bufferWidth) {
877             tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
878             sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
879                     bufferWidth;
880         }
881         if (cropRect.height() < bufferHeight) {
882             ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
883                     bufferHeight;
884             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
885                     bufferHeight;
886         }
887         float crop[16] = {
888             sx, 0, 0, 0,
889             0, sy, 0, 0,
890             0, 0, 1, 0,
891             tx, ty, 0, 1,
892         };
893 
894         mtxMul(mtxBeforeFlipV, crop, xform);
895     } else {
896         for (int i = 0; i < 16; i++) {
897             mtxBeforeFlipV[i] = xform[i];
898         }
899     }
900 
901     // SurfaceFlinger expects the top of its window textures to be at a Y
902     // coordinate of 0, so GLConsumer must behave the same way.  We don't
903     // want to expose this to applications, however, so we must add an
904     // additional vertical flip to the transform after all the other transforms.
905     mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
906 }
907 
getTimestamp()908 nsecs_t GLConsumer::getTimestamp() {
909     GLC_LOGV("getTimestamp");
910     Mutex::Autolock lock(mMutex);
911     return mCurrentTimestamp;
912 }
913 
getFrameNumber()914 uint64_t GLConsumer::getFrameNumber() {
915     GLC_LOGV("getFrameNumber");
916     Mutex::Autolock lock(mMutex);
917     return mCurrentFrameNumber;
918 }
919 
getCurrentBuffer() const920 sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
921     Mutex::Autolock lock(mMutex);
922     return (mCurrentTextureImage == NULL) ?
923             NULL : mCurrentTextureImage->graphicBuffer();
924 }
925 
getCurrentCrop() const926 Rect GLConsumer::getCurrentCrop() const {
927     Mutex::Autolock lock(mMutex);
928 
929     Rect outCrop = mCurrentCrop;
930     if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
931         uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width());
932         uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height());
933 
934         if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
935             newWidth = newHeight * mDefaultWidth / mDefaultHeight;
936             GLC_LOGV("too wide: newWidth = %d", newWidth);
937         } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
938             newHeight = newWidth * mDefaultHeight / mDefaultWidth;
939             GLC_LOGV("too tall: newHeight = %d", newHeight);
940         }
941 
942         uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width());
943         uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height());
944 
945         // The crop is too wide
946         if (newWidth < currentWidth) {
947             uint32_t dw = currentWidth - newWidth;
948             auto halfdw = dw / 2;
949             outCrop.left += halfdw;
950             // Not halfdw because it would subtract 1 too few when dw is odd
951             outCrop.right -= (dw - halfdw);
952         // The crop is too tall
953         } else if (newHeight < currentHeight) {
954             uint32_t dh = currentHeight - newHeight;
955             auto halfdh = dh / 2;
956             outCrop.top += halfdh;
957             // Not halfdh because it would subtract 1 too few when dh is odd
958             outCrop.bottom -= (dh - halfdh);
959         }
960 
961         GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
962             outCrop.left, outCrop.top,
963             outCrop.right,outCrop.bottom);
964     }
965 
966     return outCrop;
967 }
968 
getCurrentTransform() const969 uint32_t GLConsumer::getCurrentTransform() const {
970     Mutex::Autolock lock(mMutex);
971     return mCurrentTransform;
972 }
973 
getCurrentScalingMode() const974 uint32_t GLConsumer::getCurrentScalingMode() const {
975     Mutex::Autolock lock(mMutex);
976     return mCurrentScalingMode;
977 }
978 
getCurrentFence() const979 sp<Fence> GLConsumer::getCurrentFence() const {
980     Mutex::Autolock lock(mMutex);
981     return mCurrentFence;
982 }
983 
doGLFenceWait() const984 status_t GLConsumer::doGLFenceWait() const {
985     Mutex::Autolock lock(mMutex);
986     return doGLFenceWaitLocked();
987 }
988 
doGLFenceWaitLocked() const989 status_t GLConsumer::doGLFenceWaitLocked() const {
990 
991     EGLDisplay dpy = eglGetCurrentDisplay();
992     EGLContext ctx = eglGetCurrentContext();
993 
994     if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
995         GLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
996         return INVALID_OPERATION;
997     }
998 
999     if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
1000         GLC_LOGE("doGLFenceWait: invalid current EGLContext");
1001         return INVALID_OPERATION;
1002     }
1003 
1004     if (mCurrentFence->isValid()) {
1005         if (SyncFeatures::getInstance().useWaitSync()) {
1006             // Create an EGLSyncKHR from the current fence.
1007             int fenceFd = mCurrentFence->dup();
1008             if (fenceFd == -1) {
1009                 GLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
1010                 return -errno;
1011             }
1012             EGLint attribs[] = {
1013                 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
1014                 EGL_NONE
1015             };
1016             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
1017                     EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
1018             if (sync == EGL_NO_SYNC_KHR) {
1019                 close(fenceFd);
1020                 GLC_LOGE("doGLFenceWait: error creating EGL fence: %#x",
1021                         eglGetError());
1022                 return UNKNOWN_ERROR;
1023             }
1024 
1025             // XXX: The spec draft is inconsistent as to whether this should
1026             // return an EGLint or void.  Ignore the return value for now, as
1027             // it's not strictly needed.
1028             eglWaitSyncKHR(dpy, sync, 0);
1029             EGLint eglErr = eglGetError();
1030             eglDestroySyncKHR(dpy, sync);
1031             if (eglErr != EGL_SUCCESS) {
1032                 GLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
1033                         eglErr);
1034                 return UNKNOWN_ERROR;
1035             }
1036         } else {
1037             status_t err = mCurrentFence->waitForever(
1038                     "GLConsumer::doGLFenceWaitLocked");
1039             if (err != NO_ERROR) {
1040                 GLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
1041                 return err;
1042             }
1043         }
1044     }
1045 
1046     return NO_ERROR;
1047 }
1048 
freeBufferLocked(int slotIndex)1049 void GLConsumer::freeBufferLocked(int slotIndex) {
1050     GLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
1051     if (slotIndex == mCurrentTexture) {
1052         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
1053     }
1054     mEglSlots[slotIndex].mEglImage.clear();
1055     ConsumerBase::freeBufferLocked(slotIndex);
1056 }
1057 
abandonLocked()1058 void GLConsumer::abandonLocked() {
1059     GLC_LOGV("abandonLocked");
1060     mCurrentTextureImage.clear();
1061     ConsumerBase::abandonLocked();
1062 }
1063 
setName(const String8 & name)1064 void GLConsumer::setName(const String8& name) {
1065     Mutex::Autolock _l(mMutex);
1066     if (mAbandoned) {
1067         GLC_LOGE("setName: GLConsumer is abandoned!");
1068         return;
1069     }
1070     mName = name;
1071     mConsumer->setConsumerName(name);
1072 }
1073 
setDefaultBufferFormat(PixelFormat defaultFormat)1074 status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
1075     Mutex::Autolock lock(mMutex);
1076     if (mAbandoned) {
1077         GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!");
1078         return NO_INIT;
1079     }
1080     return mConsumer->setDefaultBufferFormat(defaultFormat);
1081 }
1082 
setDefaultBufferDataSpace(android_dataspace defaultDataSpace)1083 status_t GLConsumer::setDefaultBufferDataSpace(
1084         android_dataspace defaultDataSpace) {
1085     Mutex::Autolock lock(mMutex);
1086     if (mAbandoned) {
1087         GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!");
1088         return NO_INIT;
1089     }
1090     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
1091 }
1092 
setConsumerUsageBits(uint32_t usage)1093 status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
1094     Mutex::Autolock lock(mMutex);
1095     if (mAbandoned) {
1096         GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
1097         return NO_INIT;
1098     }
1099     usage |= DEFAULT_USAGE_FLAGS;
1100     return mConsumer->setConsumerUsageBits(usage);
1101 }
1102 
setTransformHint(uint32_t hint)1103 status_t GLConsumer::setTransformHint(uint32_t hint) {
1104     Mutex::Autolock lock(mMutex);
1105     if (mAbandoned) {
1106         GLC_LOGE("setTransformHint: GLConsumer is abandoned!");
1107         return NO_INIT;
1108     }
1109     return mConsumer->setTransformHint(hint);
1110 }
1111 
setMaxAcquiredBufferCount(int maxAcquiredBuffers)1112 status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
1113     Mutex::Autolock lock(mMutex);
1114     if (mAbandoned) {
1115         GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!");
1116         return NO_INIT;
1117     }
1118     return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
1119 }
1120 
dumpLocked(String8 & result,const char * prefix) const1121 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
1122 {
1123     result.appendFormat(
1124        "%smTexName=%d mCurrentTexture=%d\n"
1125        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
1126        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
1127        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
1128        mCurrentTransform);
1129 
1130     ConsumerBase::dumpLocked(result, prefix);
1131 }
1132 
mtxMul(float out[16],const float a[16],const float b[16])1133 static void mtxMul(float out[16], const float a[16], const float b[16]) {
1134     out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
1135     out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
1136     out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
1137     out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
1138 
1139     out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
1140     out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
1141     out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
1142     out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
1143 
1144     out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
1145     out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
1146     out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
1147     out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
1148 
1149     out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
1150     out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
1151     out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
1152     out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
1153 }
1154 
EglImage(sp<GraphicBuffer> graphicBuffer)1155 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
1156     mGraphicBuffer(graphicBuffer),
1157     mEglImage(EGL_NO_IMAGE_KHR),
1158     mEglDisplay(EGL_NO_DISPLAY),
1159     mCropRect(Rect::EMPTY_RECT) {
1160 }
1161 
~EglImage()1162 GLConsumer::EglImage::~EglImage() {
1163     if (mEglImage != EGL_NO_IMAGE_KHR) {
1164         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
1165            ALOGE("~EglImage: eglDestroyImageKHR failed");
1166         }
1167         eglTerminate(mEglDisplay);
1168     }
1169 }
1170 
createIfNeeded(EGLDisplay eglDisplay,const Rect & cropRect,bool forceCreation)1171 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
1172                                               const Rect& cropRect,
1173                                               bool forceCreation) {
1174     // If there's an image and it's no longer valid, destroy it.
1175     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
1176     bool displayInvalid = mEglDisplay != eglDisplay;
1177     bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
1178     if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
1179         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
1180            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
1181         }
1182         eglTerminate(mEglDisplay);
1183         mEglImage = EGL_NO_IMAGE_KHR;
1184         mEglDisplay = EGL_NO_DISPLAY;
1185     }
1186 
1187     // If there's no image, create one.
1188     if (mEglImage == EGL_NO_IMAGE_KHR) {
1189         mEglDisplay = eglDisplay;
1190         mCropRect = cropRect;
1191         mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
1192     }
1193 
1194     // Fail if we can't create a valid image.
1195     if (mEglImage == EGL_NO_IMAGE_KHR) {
1196         mEglDisplay = EGL_NO_DISPLAY;
1197         mCropRect.makeInvalid();
1198         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
1199         ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
1200             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
1201             buffer->getUsage(), buffer->getPixelFormat());
1202         return UNKNOWN_ERROR;
1203     }
1204 
1205     return OK;
1206 }
1207 
bindToTextureTarget(uint32_t texTarget)1208 void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
1209     glEGLImageTargetTexture2DOES(texTarget,
1210             static_cast<GLeglImageOES>(mEglImage));
1211 }
1212 
createImage(EGLDisplay dpy,const sp<GraphicBuffer> & graphicBuffer,const Rect & crop)1213 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
1214         const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
1215     EGLClientBuffer cbuf =
1216             static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
1217     const bool createProtectedImage =
1218             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
1219             hasEglProtectedContent();
1220     EGLint attrs[] = {
1221         EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
1222         EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
1223         EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
1224         EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
1225         EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
1226         createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
1227         createProtectedImage ? EGL_TRUE : EGL_NONE,
1228         EGL_NONE,
1229     };
1230     if (!crop.isValid()) {
1231         // No crop rect to set, so terminate the attrib array before the crop.
1232         attrs[2] = EGL_NONE;
1233     } else if (!isEglImageCroppable(crop)) {
1234         // The crop rect is not at the origin, so we can't set the crop on the
1235         // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
1236         // extension.  In the future we can add a layered extension that
1237         // removes this restriction if there is hardware that can support it.
1238         attrs[2] = EGL_NONE;
1239     }
1240     eglInitialize(dpy, 0, 0);
1241     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
1242             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
1243     if (image == EGL_NO_IMAGE_KHR) {
1244         EGLint error = eglGetError();
1245         ALOGE("error creating EGLImage: %#x", error);
1246         eglTerminate(dpy);
1247     }
1248     return image;
1249 }
1250 
1251 }; // namespace android
1252