OSDN Git Service

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